1

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?

4

1 回答 1

4

第二个scanf()调用卡住了,什么也没做,因为下一个要读取的字符是\n. scanf()不处理“空”输入,只是保持name缓冲区不变。由于name未更改,名称的第二个printf()与名称的第一个相同printf()

如果您检查 的返回值scanf(),您会注意到第二个返回了0,这意味着它没有扫描任何输入。

此代码使用的方式存在危险scanf()。由于输入说明符不告知scanf()要读取多少字节,因此输入可能会超出name缓冲区。这可能会导致未定义的行为,在最坏的情况下,会被用于堆栈粉碎攻击。scanf()您可以通过通知不要扫描太多字节来避免此问题:

    scanf( "%999s", name );

    scanf( "%999[^\n]", name );

长度必须在格式字符串中拼出 for scanf(),无法将此信息作为变量参数中的参数提供。通常认为用它fgets()来处理用户输入更可靠,然后用sscanf()它来解析它。

    /* 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;
    }
于 2013-10-10T19:08:46.353 回答