SanQA
SanQA

Reputation: 233

fgets() doesn't work as expected in C

Given the following code:

#include <stdio.h>
int main()
{
 int testcase;
 char arr[30];
 int f,F,m;
 scanf("%d",&testcase);
 while(testcase--)
 {
  printf("Enter the string\n"); 
  fgets(arr,20,stdin);
  printf("Enter a character\n");
  F=getchar();
  while((f=getchar())!=EOF && f!='\n')
    ;
  putchar(F);
  printf("\n");
  printf("Enter a number\n");
  scanf("%d",&m);
 }
 return 0;
}

I want a user to enter a string, a character and a number until the testcase becomes zero.

My doubts / questions:

1.User is unable to enter a string. It seems fgets is not working. Why?

2.If i use scanf instead of fgets,then getchar is not working properly, i.e whatever character I input in it just putchar as a new line. Why?

Thanks for the help.

Upvotes: 3

Views: 5430

Answers (3)

vishalknishad
vishalknishad

Reputation: 744

A simple hack is to write a function to interpret the newline character. Call clear() after each scanf's

void clear (void){
    int c = 0;
    while ((c = getchar()) != '\n' && c != EOF);
}

Refer to this question for further explaination: C: Multiple scanf's, when I enter in a value for one scanf it skips the second scanf

Upvotes: 1

SanQA
SanQA

Reputation: 233

Finally got the solution how can we use scanf and fgets together safely.

#include <stdio.h>
int main()
{
 int testcase,f,F,m;
 char arr[30];
 scanf("%d",&testcase);
 while((f=getchar())!=EOF && f!='\n')
  ;
 while(testcase--)
 {
  printf("Enter the string\n");
  fgets(arr,30,stdin);  
  printf("Enter a character\n");
  F=getchar();
  while((f=getchar())!=EOF && f!='\n')
    ;
  putchar(F);
  printf("\n");
  printf("Enter a number\n");
  scanf("%d",&m);
  while((f=getchar())!=EOF && f!='\n')
  ;
 }
}

We need to make sure that before fgets read anything,flushout the buffer with simple while loop.

Thanks to all for the help.

Upvotes: 1

ad absurdum
ad absurdum

Reputation: 21358

Mixing functions like fgets(), scanf(), and getchar() is error-prone. The scanf() function usually leaves a \n character behind in the input stream, while fgets() usually does not, meaning that the next call to an I/O function may or may not need to cope with what the previous call has left in the input stream.

A better solution is to use one style of I/O function for all user input. fgets() used in conjunction with sscanf() works well for this. Return values from functions should be checked, and fgets() returns a null pointer in the event of an error; sscanf() returns the number of successful assignments made, which can be used to validate that input is as expected.

Here is a modified version of the posted code. fgets() stores input in a generously allocated buffer; note that this function stores input up to and including the \n character if there is enough room. If the input string is not expected to contain spaces, sscanf() can be used to extract the string, leaving no need to worry about the newline character; similarly, using sscanf() to extract character or numeric input relieves code of the burden of further handling of the \n.

#include <stdio.h>

int main(void)
{
    int testcase;
    char arr[30];
    char F;
    int m;
    char buffer[1000];

    do {
        puts("Enter number of test cases:");
        if (fgets(buffer, sizeof buffer, stdin) == NULL) {
            /* handle error */
        }
    } while (sscanf(buffer, "%d", &testcase) != 1 || testcase < 0);

    while(testcase--)
    {
        puts("Enter the string");
        /* if string should not contain spaces... */
        if (fgets(buffer, sizeof buffer, stdin) == NULL) {
            /* handle error */
        }
        sscanf(buffer, "%29s", arr);
        printf("You entered: %s\n", arr);
        putchar('\n');

        puts("Enter a character");
        if (fgets(buffer, sizeof buffer, stdin) == NULL) {
            /* handle error */
        }
        sscanf(buffer, "%c", &F);
        printf("You entered: %c\n", F);
        putchar('\n');

        do {
            puts("Enter a number");
            if (fgets(buffer, sizeof buffer, stdin) == NULL) {
                /* handle error */
            }
        } while (sscanf(buffer, "%d", &m) != 1);

        printf("You entered: %d\n", m);
        putchar('\n');
    }

    return 0;
}

On the other hand, if the input string may contain spaces, fgets() can read input directly into arr, but then the stored string will contain a \n character, which should probably be removed. One way of doing this is to use the strcspn() function to find the index of the \n:

#include <string.h>  // for strcspn()
/* ... */
        puts("Enter the string");
        /* or, if string may contain spaces */
        if (fgets(arr, sizeof arr, stdin) == NULL) {
            /* handle error */
        }
        /* replace newline */
        arr[strcspn(arr, "\r\n")] = '\0';

        printf("You entered: %s\n", arr);
        putchar('\n');
/* ... */

Note that a maximum width should always be specified when using %s with the scanf() functions to avoid buffer overflow. Here, it is %29s when reading into arr, since arr can hold 30 chars, and space must be reserved for the null terminator (\0). Return values from sscanf() are checked to see if user input is invalid, in which case the input is asked for again. If the number of test cases is less than 0, input must be entered again.

Upvotes: 5

Related Questions