这样我就可以确认我认为正在发生的事情是否真的发生。当我将(26 个字母)字母表作为输入时,以下代码会打印出 25,是因为 fgets 总是自动将 n 个元素的数组中的第 n 个元素设置为 ' '?
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[26];
printf("String: ");
fgets(str, 26, stdin);
printf("%lu\n", strlen(str));
}
这样,当我尝试打印字母表的 strlen 时,它会在 ' 之前停止 ' 并返回我 25?
您的思考方向是正确的。
您可以查看文档(大多数情况下使用 cpp 文档来进行 c 是可以的): https://en.cppreference.com/w/c/io/fgets
它指出,签名是:
char* fgets(char* str, int count, FILE* stream);
文档说:
从给定文件流中读取最多 count - 1 个字符,并且 将它们存储在 str 指向的字符数组中。
因此,你给它一个 26 元素的数组,它最多用 25 个元素填充它并附加终止符。在 C 中,终止符是零字节 (
'\0'
)。
strlen
实际上是在给定地址之后搜索下一个终止符。它发现 str[25] == '\0'
并返回 25 作为结果。
这个地方在某些应用程序中是一个很大的安全问题 - 如果您打算使用 char*
作为空终止的 C 字符串,则应该
总是在 char 数组中添加一项额外的项目作为终止符。否则,所有函数都不会在字符串末尾停止处理 - 它们仅对指针进行操作,并且在大多数情况下没有给出
len
参数。
当您在终端中输入某个字符串时,您可以使用回车符(换行符)来终止该输入。在 Linux 中它只是
"\n"
(1 个字节),而在 Windows 上它是 "\r\n"
(2 个字节)。
假设您输入了
John
并按 Enter。流将包含:
"John\n"
- 即 5 个字节。 Byt 来存储此文本并在 printf
的 %s
替换中使用它,或者说,strlen
,您还应该存储一个浮动空终止符。因此您可能需要分配至少 6 个字节:
str[6] = {'J', 'o', 'h', 'n', '\n', '\0'};
当您调用 strlen 时,它将返回自给定指针以来的非零元素计数 - 即 5。 如果您随后将重用该数组并存储,例如仅“?”,那么您将拥有:
str[6] = {'?', '\n', '\0', 'n', '\n', '\0'};
注意,
strlen
将返回2,而\0
之后数组不会被清除。所有函数都将忽略第一个检测到的 '\0'
字符之后的数据,并且 printf(例如)将仅“看到”"?\n"
。