在C中有这样的语法吗? %[^ \ n] S

时间:2016-05-09 13:26:27

标签: c string syntax scanf

我班上的一位同学告诉我,在使用scanf扫描字符串但没有限制时会使用该语法。我的意思是,你可以使用scanf扫描一个字符串,它仍会扫描空格。

    scanf("%[^\n]s",&string);

1 个答案:

答案 0 :(得分:3)

scanf( "%[^\n]", string );将读取并将所有换行符(但不包括在内)存储到string 1 中。与s转换说明符不同,它不会跳过任何前导空格(空格,制表符等)。

如上所述,此代码易受缓冲区溢出 2 的影响;如果string的大小设置为容纳10个字符而某人输入100个字符,那么这些额外的字符将在string之后立即写入内存,这可能会导致各种混乱。

至少,您需要添加字段宽度说明符,例如

scanf( "%10[^\n]", string );

表示“在string中读取不超过10个字符”。不幸的是,字段宽度必须指定为格式字符串的一部分;与scanf不同,printf没有为您提供将字段宽度指定为参数的方法。

您可以动态构建格式字符串,例如:

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

<小时/>

  1. 意味着输入流中会有一个流浪的换行符,这可能会也可能不会导致下一个输入出现问题。
  2. 它或多或少在功能上等同于gets库函数,由于这个原因,它已从C 2011中删除(参见chux下面的“或更少”部分的评论)。