当gets()读取一个换行符时,它会保存什么?

3
以下是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""

3
你不能用 == 来比较字符串,你需要使用 strcmp 函数。(或者你可以使用 input[0] == '\n'input[0] == '\0'。) - molbdnilo
1
你不能将字符串和字符进行比较,input == '\0' 应该改为 *input == '\0' - David Ranieri
哦,还有 input == '\0' 相当于 input == 0 - molbdnilo
1
增加编译器的警告级别。它应该告诉你正在比较指针和整数,并且 gets 已经过时了。 - Jens Gustedt
1
永远不要使用gets(3) - user2371524
现在已经没有名为gets()的函数了,它已经从C语言中移除。因此,研究该函数的意义有限。请专注于使用和理解fgets()函数。 - Lundin
2个回答

3

它将字符串设置为"",即{'\0'}。不过不要使用gets(),因为它会导致缓冲区溢出。


1
但它存储它们时,“不包括”换行符。 - Davislor
确实,这是我的错...从来没有使用过gets()就会发生这种情况 ;) - user2371524
谢谢,这很有道理。 - User314159

3

gets的描述部分可能会有些困惑:

它获取到(但不包括)换行符之前的所有字符。

更好的说法可能是,它获取包括换行符在内的所有字符,但是存储除了换行符之外的所有字符。

所以,如果用户输入some stringgets函数将从用户终端读取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("第一个字节是否包含字符串结束字符?%d\n", input [0] =='\ 0');

这只比较了1个字节和\0


printf("它是换行符吗?%d\n", input=="\n");

不好:这将缓冲区地址与"\n"的地址进行比较-答案始终为false。在C中比较字符串的正确方法是使用strcmp

printf("它是换行符吗?%d\n", strcmp(input,"\n")==0);

请注意奇特的用法:strcmp在字符串相等时返回0。


printf("它是空字符串吗?%d\n", input=="");

这里也有同样的错误。在这里使用strcmp

printf("它是空字符串吗?%d\n", strcmp(input, "") == 0);


顺便说一下,正如人们经常说的那样,gets不能以安全的方式使用,因为它不支持缓冲区溢出的保护。所以你应该使用fgets,即使它不太方便:
char input[100];
while (fgets(input, sizeof input, stdin))
{
    ...
}

这可能会导致困惑: fgets 并不删除输入中的换行符。因此,如果您将代码中的 gets 替换为 fgets,你将得到不同的结果。幸运的是,你的代码将以明显的方式展示这种差异。

感谢您的详细解释。 - User314159

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接