gets() 只读取一个换行符时保存了什么
What does gets() save when it reads just a newline
这是 Prata 的 C Primer Plus 中对 gets()
的描述:
It gets a string from your system's standard input device, normally
your keyboard. Because a string has no predetermined length, gets()
needs a way to know when to stop. Its method is to read characters
until it reaches a newline (\n
) character, which you generate by
pressing the Enter key. It takes all the characters up to (but not
including) the newline, tacks on a null character ([=15=]
), and gives the
string to the calling program.
这让我很好奇当 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 == '[=10=]');
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
到底是什么?这似乎不是我的任何猜测:[=15=]
或 \n
或 ""
.
它将字符串设置为""
,即{'[=11=]'}
。但是不要使用 gets()
。它会导致缓冲区溢出。
gets
的描述中的这一部分可能令人困惑:
It takes all the characters up to (but not including) the newline
最好说它需要所有字符包括换行符但存储 所有字符 不包括 换行符。
所以如果用户输入some string
,gets
函数将从用户的终端读取some string
和换行符,但在缓冲区中只存储some string
- 换行符丢失。这很好,因为反正没有人想要换行符 - 它是一个控制字符,而不是用户想要输入的数据的一部分。
因此,如果您只按输入,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 == '[=19=]');
不好:您想在这里检查 1 个字节,而不是整个缓冲区。如果您尝试将整个缓冲区与 0 进行比较,答案始终是 false
,因为编译器将 [=21=]
转换为 NULL
并将比较解释为 "does the buffer exist at all?".
正确的做法是:
printf("Does the first byte contain the string end character? %d\n", input[0] == '[=23=]');
这与 [=21=]
相比只有 1 个字节。
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
returns 当字符串相等时为 0。
printf("Is it the empty string? %d\n", input == "");
同样的错误。在这里也使用 strcmp
:
printf("Is it the empty string? %d\n", strcmp(input, "") == 0);
顺便说一句,正如人们常说的那样,gets
不能以安全的方式使用,因为它不支持缓冲区溢出保护。所以你应该使用 fgets
代替,即使它不太方便:
char input[100];
while (fgets(input, sizeof input, stdin))
{
...
}
这可能会导致混淆:fgets
不会从它读取的输入中删除换行字节。因此,如果您将代码中的 gets
替换为 fgets
,您将得到不同的结果。幸运的是,您的代码将以清晰的方式说明差异。
这是 Prata 的 C Primer Plus 中对 gets()
的描述:
It gets a string from your system's standard input device, normally your keyboard. Because a string has no predetermined length,
gets()
needs a way to know when to stop. Its method is to read characters until it reaches a newline (\n
) character, which you generate by pressing the Enter key. It takes all the characters up to (but not including) the newline, tacks on a null character ([=15=]
), and gives the string to the calling program.
这让我很好奇当 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 == '[=10=]');
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
到底是什么?这似乎不是我的任何猜测:[=15=]
或 \n
或 ""
.
它将字符串设置为""
,即{'[=11=]'}
。但是不要使用 gets()
。它会导致缓冲区溢出。
gets
的描述中的这一部分可能令人困惑:
It takes all the characters up to (but not including) the newline
最好说它需要所有字符包括换行符但存储 所有字符 不包括 换行符。
所以如果用户输入some string
,gets
函数将从用户的终端读取some string
和换行符,但在缓冲区中只存储some string
- 换行符丢失。这很好,因为反正没有人想要换行符 - 它是一个控制字符,而不是用户想要输入的数据的一部分。
因此,如果您只按输入,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 == '[=19=]');
不好:您想在这里检查 1 个字节,而不是整个缓冲区。如果您尝试将整个缓冲区与 0 进行比较,答案始终是 false
,因为编译器将 [=21=]
转换为 NULL
并将比较解释为 "does the buffer exist at all?".
正确的做法是:
printf("Does the first byte contain the string end character? %d\n", input[0] == '[=23=]');
这与 [=21=]
相比只有 1 个字节。
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
returns 当字符串相等时为 0。
printf("Is it the empty string? %d\n", input == "");
同样的错误。在这里也使用 strcmp
:
printf("Is it the empty string? %d\n", strcmp(input, "") == 0);
顺便说一句,正如人们常说的那样,gets
不能以安全的方式使用,因为它不支持缓冲区溢出保护。所以你应该使用 fgets
代替,即使它不太方便:
char input[100];
while (fgets(input, sizeof input, stdin))
{
...
}
这可能会导致混淆:fgets
不会从它读取的输入中删除换行字节。因此,如果您将代码中的 gets
替换为 fgets
,您将得到不同的结果。幸运的是,您的代码将以清晰的方式说明差异。