当只读取换行符时,gets()会保存什么
这是来自Prata的C Primer Plus的gets()
的描述:
它从系统的标准输入设备(通常是键盘)中获取一个字符串。 因为字符串没有预定长度,所以gets()需要一种知道何时停止的方法。 它的方法是读取字符,直到它到达换行符(\ n),然后按Enter键生成。 它将所有字符带到(但不包括)换行符,对空字符(\ 0)进行处理,并将字符串提供给调用程序。
我很好奇当gets()
读取换行符时会发生什么。 所以我写了这个:
int main(void) { char input[100]; while(gets(input)) { printf("This is the input as a string: %s\n", input); printf("Is it the string end character? %d\n", input == '\0'); printf("Is it a newline string? %d\n", input == "\n"); printf("Is it the empty string? %d\n", input == ""); } return 0; }
这是我与该计划的互动:
$ ./a.out This is some string This is the input as a string: This is some string Is it the string end character? 0 Is it a newline string? 0 Is it the empty string? 0 This is the input as a string: Is it the string end character? 0 Is it a newline string? 0 Is it the empty string? 0
当我按下的所有内容都输入时,第二个块真的是感兴趣的东西。 在这种情况下究竟input
了什么? 它似乎不是我的任何猜测: \0
或\n
或""
。
gets
描述中的这一部分可能会令人困惑:
它将所有角色带到(但不包括)换行符
最好说它包含所有字符, 包括换行符,但存储所有不包括换行符的字符。
因此,如果用户输入some string
,则gets
函数将从用户的终端读取some string
和换行符,但只在缓冲区中存储some string
– 换行字符丢失。 这很好,因为无论如何都没有人想要换行符 – 它是一个控制字符,而不是用户想要输入的数据的一部分。
因此,如果您只按Enter键,则会gets
解释为空字符串。 现在,正如一些人所指出的,您的代码有多个错误。
printf("This is the input as a string: %s\n", input);
这里没问题,尽管您可能想要通过一些人工字符来划分字符串以获得更好的调试:
printf("This is the input as a string: '%s'\n", input);
printf("Is it the string end character? %d\n", input == '\0');
不好:你想在这里检查1个字节,而不是整个缓冲区。 如果您尝试将整个缓冲区与0进行比较,则答案始终为false
因为编译器将\0
转换为NULL
并将比较解释为“缓冲区是否存在?”。
正确的方法是:
printf("Does the first byte contain the string end character? %d\n", input[0] == '\0');
这只比较1个字节到\0
。
printf("Is it a newline string? %d\n", input == "\n");
不好:这会将缓冲区的地址与"\n"
的地址进行比较 – 答案始终为false
。 在C中比较字符串的正确方法是strcmp
:
printf("Is it a newline string? %d\n", strcmp(input, "\n") == 0);
请注意特殊用法:当字符串相等时, strcmp
返回0。
printf("Is it the empty string? %d\n", input == "");
同样的错误在这里。 在这里也使用strcmp
:
printf("Is it the empty string? %d\n", strcmp(input, "") == 0);
人们总是说BTW不能以安全的方式使用,因为它不支持缓冲区溢出保护。 所以你应该使用fgets
,即使它不太方便:
char input[100]; while (fgets(input, sizeof input, stdin)) { ... }
这可能导致混淆: fgets
不会从它读取的输入中删除换行字节。 因此,如果您通过fgets
替换代码中的get,您将得到不同的结果。 幸运的是,您的代码将以清晰的方式说明差异。
它将字符串设置为""
,即{'\0'}
。 但是,不要使用gets()
。 它会导致缓冲区溢出。