0

The book_name is picking \n as input a printing the next variable in a new line. I inserted this code while ((getchar()) != '\n'); to prevent fgets() from taking \n as input after using scanf(). But i can't understand why fgets() is taking \n as input. Please explain.

CODE

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

typedef struct {
    int id;
    char *book_name;
    char *author;
} book;

int main() {
    int n;

    printf("Enter number of books: \n");
    scanf("%d", &n);

    book *bk = calloc(n, sizeof(book));

    for (int i = 0; i < n; i++)
    {
        printf("Enter the no of the book: \n");
        scanf("%d", &((bk+i)->id));

        while ((getchar()) != '\n');

        (bk+i)->book_name = malloc(20);
        printf("Enter the name of the book: \n");
        fgets((bk+i)->book_name, 20, stdin);

        (bk+i)->author = malloc(20);
        printf("Enter the author of the book: \n");
        fgets((bk+i)->author, 20, stdin);
    }

    for (int i = 0; i < n; i++)
    {
        printf("%d %s %s\n", (bk+i)->id, (bk+i)->book_name, (bk+i)->author);
    }
    
    
    return 0;
}

OUTPUT

Output of code

  • 3
    "why fgets() is taking \n as input." --> that is what `fgets()` does. – chux - Reinstate Monica Sep 17 '20 at 03:19
  • See [Removing trailing newline character from fgets() input](https://stackoverflow.com/q/2693776/2410359) Likely dupe. – chux - Reinstate Monica Sep 17 '20 at 03:25
  • Note that the loop `while ((getchar()) != '\n');` should be `int c; while ((c = getchar()) != EOF && c != '\n') ;` — If you get EOF before you read a newline, you will spend a long time in the loop (and it can happen!). – Jonathan Leffler Sep 17 '20 at 03:46
  • You will also run into problems when someone enters a title such as "The Anatomy of a Disaster" (which is more than 18 characters long). Similarly, if the 'author' is "William Shakespeare & Francis Bacon", you'll have problems. You should check that the `scanf()` and `fgets()` calls are successful too. I/O has a horrid habit of failing when you don't check it. – Jonathan Leffler Sep 17 '20 at 03:50

1 Answers1

0

Check answered post here.

scanf() leaves '\n' in the buffer. So whenever any other function such as getchar() or fgets() tries to read from the stdin, leftover '\n' is read first.

If you are on file instead of stdin, better use below code for extra safety.

FILE *fp = fopen("my_file.txt", "r");
int c;
while ((c = fgetc(fp)) != EOF && c != '\n');

What you have done is the correct way to remove leftover \n, @sadbro probably misunderstood your code.

Lazy Ren
  • 704
  • 6
  • 17
  • 1
    There is useful advice in this answer, but it is not well explained. The second paragraph is accurate. The code snippet is OK as long as the input is coming from `stdin`; if it comes from some other file stream, `fp`, you need `int c; while ((c = getc(fp)) != EOF && c != '\n') ;` (I'd put the semicolon on a line on its own, but that's stylistic — for all it matches what K&R suggest.). The code in the question is close to correct for removing the newline before using `fgets()` — but it doesn't check for EOF. – Jonathan Leffler Sep 17 '20 at 03:54
  • Thank you for the accurate and detailed explanation. I've changed my code to use getc() with file pointer & to usechar variable. – Lazy Ren Sep 17 '20 at 07:03
  • You should note that I use an `int` and not a `char` because `getchar()` and `getc()` and `fgetc()` all return an `int` and not a `char`. That's because they all return any possible `char` value and a distinct negative value known as `EOF`. You cannot store all those in a `char`. See also [`while ((c = get(file)) != EOF)` loop won't stop executing](https://stackoverflow.com/a/13694450/15168). – Jonathan Leffler Sep 17 '20 at 07:07
  • Ah...yes indeed. `EOF` itself is represented as `-1`. I'll put more attention to my answers to prevent such errors for next time. Thank you. – Lazy Ren Sep 17 '20 at 07:36
  • @LazyRen you should use **fgetc** instead of **getc** because it's deprecated from the C language standard – Saadi Toumi Fouad Sep 17 '20 at 07:53