Using fscanf () vs. fgets () and sscanf ()

In the book Practical C Programming, I found that the combination of fgets() and sscanf() used to read input. However, it seems to me that for the same purpose it is easier to deal with the fscanf() function:

From the book (idea, not an example):

 int main() { int age, weight; printf("Enter age and weight: "); char line[20]; fgets(line, sizeof(line), stdin); sscanf(line, "%d %d", &age, &weight); printf("\nYou entered: %d %d\n", age, weight); return 0; } 

As I think it should be:

 int main() { int age, weight; printf("Enter age and weight: "); fscanf(stdin, "%d %d", &age, &weight); printf("\nYou entered: %d %d\n", age, weight); return 0; } 

Or is there some hidden quirk that I miss?

+7
c
source share
3 answers

In the two approaches, there are several differences in behavior. If you use fgets() + sscanf() , you must enter both values ​​on the same line, while fscanf() on stdin (or, what is the same, scanf() ) will read them from different lines if it does not find the second value in the first line entered.

But perhaps the most important differences are related to error handling and the mixing of linear oriented input and field oriented input.

If you read a line that you cannot parse with sscanf() after reading it with fgets() , your program may simply discard the line and move on. However, fscanf() , when it cannot convert fields, leaves all the input in the stream. So, if you were unable to read the input you entered, you have to go and read all the data that you want to ignore.

Another subtle getcha comes if you want to mix field-oriented (ala scanf() ) with lines (like fgets() ) in your code. If scanf() converts an int , for example, it will leave the input stream \n behind (if it is, for example, by pressing the enter key), which will cause a subsequent call to fgets() to return immediately with this character in the input. This is a very common problem for new programmers.

So, although you are correct that you can just use fscanf() like this, you can avoid some headaches by using fgets() + sscanf() .

+10
source share

The only problem with using fscanf() is mainly error management.

Imagine that you enter β€œ 51 years, 85 kg ” for both programs.

The first program crashes in sscanf() , and you still have a line to report errors to the user, try another parsing alternative, something;

The second program does not work for years , age can be used, weight unusable.

Remember to always check the return value of *scanf() for error checking.

  fgets(line, sizeof(line), stdin); if (sscanf(line, "%d%d", &age, &weight) != 2) /* error with input */; 

Edit

With your first program after an error, the input buffer is clear; with the second program, the input buffer starts with YEAR ...

Recovery in the first case is easy; recovery in the second case should go through some flushing of the input buffer.

+4
source share

There is no difference between fscanf() and fgets() / sscanf() when:

  • The input is well formed.

Two types of errors occur: input-output and format. fscanf() handles these two types of errors simultaneously in one function, but offers several recovery options. Separate fgets() and sscanf() allow a logical separation of input / output problems from the format and, therefore, a better recovery.

  1. Only one way to parse.

Disabling I / O from scanning allows you to use several sscanf() options. If the specified buffer scan does not realize the desired results, other sscanf() with different formats are available.

  1. No built-in '\0' .

Rarely does '\0' occur, but if that happens, sscanf() will not see it, because scanning will stop when it occurs, while fscanf() continues.

In all cases, check the results of all three functions.

+1
source share

All Articles