[ACCEPTED]-Parsing input with scanf in C-scanf

Accepted answer
Score: 19

When you enter "c P101" the program actually receives 25 "c P101\n". Most of the conversion specifiers skip 24 leading whitespace including newlines but 23 %c does not. The first time around everything 22 up til the "\n" is read, the second time around 21 the "\n" is read into command, "c" is read into 20 prefix, and "P" is left which is not a number so 19 the conversion fails and "P101\n" is left on the 18 stream. The next time "P" is stored into 17 command, "1" is stored into prefix, and 1 (from 16 the remaining "01") is stored into input with 15 the "\n" still on the stream for next time. You 14 can fix this issue by putting a space at 13 the beginning of the format string which 12 will skip any leading whitespace including 11 newlines.

A similiar thing is happening for 10 the second case, when you enter "q", "q\n" is 9 entered into the stream, the first time 8 around the "q" is read, the second time the 7 "\n" is read, only on the third call is the 6 second "q" read, you can avoid the problem 5 again by adding a space character at the 4 beginning of the format string.

A better 3 way to do this would be to use something 2 like fgets() to process a line at a time 1 and then use sscanf() to do the parsing.

Score: 1

For question 1, I suspect that you've got 16 a problem with your printf(), since there is no 15 terminating "\n".

The default behavior of 14 printf is to buffer output until it has a complete 13 line. That is unless you explicitly change 12 the buffering on stdout.

For question 2, you've 11 just hit one of the biggest problems with 10 scanf(). Unless your input exactly matches the 9 scan string that you've specified, your 8 results are going to be nothing like what 7 you expect.

If you've got an option you'll 6 have better results (and fewer security 5 issues) by ignoring scanf() and doing your own 4 parsing. For example, use fgets() to read an entire 3 line into a string, and then process the 2 individual fields of the string — maybe 1 even using sscanf().

Score: 1

It's really broken! I didn't know it

#include <stdio.h>

int main(void)
{
    int counter = 1;
    char command, prefix;
    int input;

    do 
    {
        printf("counter: %d: ", counter);
        scanf("%c %c%d", &command, &prefix, &input);
        printf("---%c %c%d---\n", command, prefix, input);
        counter++;
    } while (command != 'q');
}
counter: 1: a b1
---a b1---
counter: 2: c d2
---
 c1---
counter: 3: e f3
---d 21---
counter: 4: ---e f3---
counter: 5: g h4
---
 g3---

The 1 output seems to fit with Robert's answer.

Score: 1

Once you have the string that contains the 2 line. i.e. "C P101", you can use 1 the parsing abilities of sscanf.

See: http://www.cplusplus.com/reference/clibrary/cstdio/sscanf.html

Score: 0

Perhaps using a while loop, not a do...while 23 loop will help. This way the condition is 22 tested before execution of the code. Try 21 the following code snippet:

 while(command != 'q')
    {
        //statements
    }

Also, if you 20 know the string length ahead of time, 'for' loops 19 can be much easier to work with than 'while' loops. There 18 are also some trickier ways to dynamically 17 determine the length as well.

As a final 16 rant: scanf() does not "suck." It does 15 what it does and that is all.

The gets() function is very dangerous (though 14 convenient for no-risk applications), since 13 it does not natively do any checking of 12 the input. It is VERY commonly known as 11 a point of exploit, specifically buffer 10 overflow attacks, overwriting space in registers 9 not allocated for that variable. Therefore 8 if you choose to use it, spend some time 7 putting some solid error checking/correction 6 in.

However, almost invariably, either fgets() or 5 POSIX getline() should be used to read the line — noting 4 that the functions both include the newline 3 in the input string, unlike gets(). You can remove 2 the trailing newline from string read by either 1 fgets() or getline() using string[strcspn(string, "\n")] = '\0'; — this works reliably.

More Related questions