为什么这里的strlen等于25?

问题描述 投票:0回答:2

这样我就可以确认我认为正在发生的事情是否真的发生。当我将(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?

c printf c-strings fgets strlen
2个回答
1
投票

如果整行适合缓冲区,根据您的大小参数(在您的情况下是

26
),其中包括字符串空终止符,那么
fgets
将添加换行符。

如果整行适合缓冲区,那么

fgets
将不会添加换行符,只会添加适合缓冲区的内容(包括空终止符)。

因此,如果您输入超过

25
个字符(不包括换行符),那么长度将始终为
25


另一方面,您应该始终检查

fgets
返回的内容。

并且

strlen
函数返回
size_t
类型的值,其正确的
printf
格式为
%zu

如果可能,请在使用

sizeof
时使用
fgets
。正如
fgets(str, sizeof str, stdin)


0
投票

您的思考方向是正确的。

您可以查看文档(大多数情况下使用 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
参数。

感谢@some-programmer-dude。不得不提的是:

当您在终端中输入某个字符串时,您可以使用回车符(换行符)来终止该输入。在 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"

© www.soinside.com 2019 - 2024. All rights reserved.