How to use fgets properly in a structure?
Asked Answered
A

2

6

I can't work out what's the problem with my code. Here's my code:

#include <stdio.h>
#include <stdlib.h>    

#define N 20

typedef struct _dog {
    char dogName[N],ownerName[N];
    int dogAge;
} Dog;

int main() {
    //Dynamic array
    int size;
    printf("Number of dogs: ");
    scanf("%d", &size);
    Dog *dog = (Dog*)malloc(sizeof(Dog)*size);
    printf("\n");
    //Input
    int i;
    printf("Please provide the data: [dogName][ownerName][dogAge] :\n");
    for(i=0;i<size;i++) {
        fgets(dog[i].dogName, sizeof(dog[i].dogName), stdin);
        fgets(dog[i].ownerName, sizeof(dog[i].ownerName), stdin);
        scanf("%d", &dog[i].dogAge);
    }
    //Output
    printf("\nYou provided the following data:\n");
    for(i=0;i<size;i++) {
        printf("Dog Name: %s\nOwner Name: %s\nDog Age: %d\n", dog[i].dogName, dog[i].ownerName, dog[i].dogAge);
    }

    free(dog);
    return 0;
}

The task is pretty easy, you have to make a database but the dogs and owners can have two or more names, so that's why i try to use fget. But the output looks awful: (And the first Dog name part is usually blank)

You provided the following data:
Dog Name: 

Owner Name: Doggy 1

Dog Age: 0
Dog Name: Big Dick

Owner Name: 2

Dog Age: 0

I've read this but didn't help me.

The input I used:

Doggy 1
Big Dick
2
Doggy 2

It's ended after Doggy 2.

Assay answered 27/12, 2015 at 14:16 Comment(6)
Please see this discussion on why not to cast the return value of malloc() and family in C..Coverdale
Could you show your input, please?Buckbuckaroo
@cad Added! But it seems we've found the main problem.Assay
@SouravGhosh Thanks, I will read the post!Assay
@M.Carver Please do not add the answer in the question. Also, you can read this, if it helps. ;)Coverdale
@SouravGhosh Thanks for the clarification, that's what I tried to find. You readin' my mind. :)Assay
C
11

You are leaving a newline from your last scanf() which is a valid input for the fgets(). Change

scanf("%d", &size);

to

scanf("%d%*c", &size);

to consume and discard the trailing newline due to the press of ENTER key after entering the number of dogs.

The same goes for the dogAge variable scanning, too, inside the lop.

Related, quoting the C11 standard, chapter §7.21.6.2, fscanf()

Trailing white space (including new-line characters) is left unread unless matched by a directive. [...]

so, the newline ('\n'), the trailing white space, is left unread in the input buffer.

Coverdale answered 27/12, 2015 at 14:20 Comment(7)
Thank you for the fast reply. I've added the code at the size part but it seems I've still got a bug in my code in the loop where i use scanf. If I understand right the scanf in the loop creates a newline too? UPDATE: I've added %d%*c at the scanf in the loop, now works like a charm. :) Is there a better way to consume newlines after scanf or I have to use this all the time?Assay
@SouravGhosh I downvoted it. No offense please, but I tested it and it does not work. Does it work for you?Hydrothorax
@Elyasin I did not test the functionality, but I see no reason for this to fail. Can you share your test please?Coverdale
Both @Elyasin and Sourav Ghosh answer is working, now i understand what was the problem. Thanks for both of you! UPDATE: I used %d%*c at both scanf in code, and works the same as getchar();Assay
Oh dear, I retested it and it works. I'm sorry, my bad :-(Hydrothorax
Our interactions might have interleaved. In the beginning you forgot to mention the scanf in the inner loop. That's when my test failed. Now that I did it again it works after the edit it works. The answer is correct I think (y)Hydrothorax
@Elyasin ha ha. I did not forget, I thought it was understood. However, later I thought of adding the last line too, and see, it helps . :)Coverdale
H
3

Add a getchar() after the scanf(...) calls.

As in the other answer(s) mentioned. scanf consumes the recognized characters according to format, but leaves the newline \n in stdin. With getchar you consume it and subsequent reads from stdin should not get confused.

Hydrothorax answered 27/12, 2015 at 14:21 Comment(1)
@Elyasin If I add getchar(); after the two scanf it works too, thanks for the help. You guys rock!Assay

© 2022 - 2024 — McMap. All rights reserved.