scanf( "%[^\n]", string ); 将读取所有直到(但不包括)换行符的所有内容到string1。与s 转换说明符不同,它不会跳过任何前导空格(空格、制表符等)。
正如所写,这段代码容易受到缓冲区溢出的影响2;如果string 的大小可以容纳10 个字符,而有人输入了100 个字符,那么这些多余的字符将紧跟string 写入内存,这可能会导致各种混乱。
至少,您会想要添加一个字段宽度说明符,例如
scanf( "%10[^\n]", string );
表示“将不超过 10 个字符读入string”。不幸的是,必须将字段宽度指定为格式字符串的一部分;与printf 不同,scanf 不提供将字段宽度指定为参数的方法。
您可以动态构建格式字符串,例如:
char fmt[20];
char string[11] = {0};
sprintf( fmt, "%%%zu[^\n]", sizeof string - 1 );
scanf( fmt, string ); // fmt contains the string "%10[^\n]"
这样您就不必对字段宽度进行硬编码。
或者,您可以完全避免胃灼热,而只使用fgets:
char string[11];
...
fgets( string, sizeof string, stdin );
语义上的主要区别在于fgets 将将换行符存储到string(如果有空间),因此如果您不希望字符串中出现换行符,您将拥有手动删除:
char *newline = strchr( string, '\n' );
if ( newline )
*newline = 0; // overwrite newline character with 0 terminator
- 这意味着您将在输入流中出现一个杂散的换行符,这可能会也可能不会导致下一个输入出现问题。
- 它在功能上或多或少等同于
gets 库函数,正是出于这个原因,它已从 C 2011 中删除(有关“或更少”部分,请参见下面 chux 的评论)。