Here is a part of my code. The aim of gets
and sscanf
is to scan three variables separated by exactly one space. If passed, then output the instruction again. Otherwise, output error and exit program.
I want to use 7 length char array to limit the number in the line, getting format like 'g 3 3' only. But it seems something wrong in my code.
#include <stdio.h>
int main (void) {
char line[7];
char command;
int x, y;
while(1){
/* problem: g 4 4 or g 4 4 can also pass */
fgets(line, 7, stdin);
nargs = sscanf(line, "\n%c %d %d", &command, &x, &y);
if(nargs != 3){
printf("error\n");
return 0;
}
printf("%c %d %d\n", command, x, y);
}
}
Unexpected:
g 4 4
g 4 4
error
expected:
g 4 4
g 4 4
// I can continue type
Can anyone tell me why it will still repeat the instruction?
you have a problem with program ? gdb is your best friend =)
and then step through the statements, whenever you encounter scanf or printf just type finish, what you will see is that the program completed this iteration successfully but then the program did not wait for input and just printed error message ? why ? well type :
fgets reads at most ONE LESS than size, so in your case, fgets is only allowed to read 6 characters, but you gave it 7! Yes the newline is a character just like the space, so what happens to the 7th ? it will be buffered, which means that instead of reading from the keyboard, your program will see that there are characters in the buffer and will use them( one character in this example ). Edit : Here is what you can do to make your program work
you can ignore empty lines, if ( strccmp(line, "\n") == 0 ) then jump to the next iteration, and if you are not allowed to use strcmp a workaround would be comparing line[0]=='\n'.
What you have there won't work, since
sscanf()
won't be bothered if the user inputs one or two whitespaces.You could approach this in a simple way, by taking advantage of short circuiting and by using getchar(), like this:
Output:
The tricky part is that
"%d"
consumes leading white-space, so code needs to detect leading white-space first." "
consumes 0 or more white-space and never fails.So
"\n%c %d %d"
does not well detect the number of intervening spaces.If the
int
s can be more than 1 character, use this, else see below simplification.Use
"%n
to detect location in the buffer ofsscanf()
progress.It gets the job done using
sscanf()
which apparently is required.Maybe add test to insure
command
is not a whitespace, but I think that will happen anyway in command processing.A simplification can be had if the
int
s must only be 1 digit and with a mod combining @Seb answer with the above. This works because the length of each field is fixed in an acceptable answer.@Seb and I dove into the need for checking the return value of
sscanf()
. Although thecnt == 3
test is redundant sincen == 5
will only be true when then entire line was scanned andsscanf()
returns 3, a number of code checkers may raise a flag noting that the results ofsscanf()
is not checked. Not qualifying the results ofsscanf()
before using the saved variables is not robust code. This approach uses a simple and sufficient check ofn == 5
. Since many code problems stem from not doing any qualification, the lack of the check of thesscanf()
can raise a false-positive amongst code checkers. Easy enough to add the redundant check.According to the C11 standard, 7.21.6.2p5:
This describes the
\n
directive and the two space characters as being identical in functionality: They'll match as much consecutive white-space (spaces, tabs, newlines, etc) as they can from the input.If you want to match a single space (and only a single space), I suggest using
%*1[ ]
instead of the white-space directives. You could use%*1[\n]
to similarly discard a newline. For example, since the newline character appears at the end of a line:This won't completely solve your problem, unfortunately, as the
%d
format specifier is also defined to discard white-space characters:With some clever hacks, you might be able to continue using
sscanf
(or better yet,scanf
without the intermediate buffer), but after comparing the alternatives in terms of cost on maintainability, we might as well just usegetchar
, so if you're looking for a solution to your problem as opposed to an answer to the question you posed, I'd recommend gsamaras answer.