Reputation: 898
I'm having a bit of difficulty understanding some C code my professor has given me. The code is as follows:
#include <stdio.h>
#include <stdlib.h>
int main()
{
char name[1000];
printf( "What's your name? " );
scanf( "%s", name );
printf( "name is %s\n", name );
scanf( "%[^\n]", name ); /* read the entire line (up to but not
including the '\n' at then end) */
getchar(); /* consume the newline from the input */
printf( "name is %s\n", name );
return EXIT_SUCCESS;
}
The user enters a name and has it printed out twice as such:
What's your name? Dan
name is Dan
name is Dan
It confuses me how this works. The prompt is printed with printf, input is read into the buffer with scanf, and the buffer is printed with printf. However, the \n in the second printf should clear the buffer, so from where is the second scanf reading? I would think it would wait for user input (given an empty buffer) but it doesn't, it simply knows the name. How does this work?
Upvotes: 1
Views: 497
Reputation: 70472
The second scanf()
call jammed, and did nothing, because the next character to read was the \n
. scanf()
does not deal with "empty" input, and just left the name
buffer unchanged. Since name
was unchanged, the second printf()
of the name is the same as the first printf()
of the name.
If you checked the return value of scanf()
, you would have noticed that the second one returned 0
, meaning that it did not scan any input.
There is a danger in the way that this code uses scanf()
. Since the input specifiers does not inform scanf()
about how many bytes to read, the input can potentially overrun the name
buffer. This can lead to undefined behavior, and in the worst case, be used in a stack smash attack. You can protect from this problem by informing scanf()
not to scan too many bytes:
scanf( "%999s", name );
scanf( "%999[^\n]", name );
The length has to be spelled out in the format string for scanf()
, there is no way to provide this information as an argument within the variable arguments. It is usually considered more reliable to use fgets()
to deal with the user input, and then use sscanf()
to parse it.
/* get the name */
char input[sizeof(name)];
input[sizeof(input)-2] = '\n'
if ( fgets( input, sizeof(input), stdin ) != 0 ) {
if ( sscanf( "%s", name ) == 0 ) name[0] = '\0';
}
/* get the rest of the line in case it was really long */
while ( input[sizeof(input)-2] && input[sizeof(input)-2] != '\n' ) {
input[sizeof(input)-2] = '\n';
if ( fgets( input, sizeof(input), stdin ) == 0 ) break;
}
Upvotes: 4