Sizeof与Strlen的区别

46
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    char string[] = "october"; // 7 letters

    strcpy(string, "september"); // 9 letters

    printf("the size of %s is %d and the length is %d\n\n", string,
        sizeof(string), strlen(string));

    return 0;
}

输出:

$ ./a.out
the size of september is 8 and the length is 9

我的语法有问题吗?


11
你正在数组string的结尾处写入内容,这是未定义的行为。string只能容纳8个字符("october"有7个字符,再加上一个空字符作为字符串结束符)。当你调用strcpy函数时,你将会向其写入10个字符("september"有9个字符,再加上一个空字符作为字符串结束符),这意味着你超出了数组的结尾,正在覆盖相邻的内存。 - Marlon
14
请注意,sizeof 是在编译时计算的,而 strlen 是在运行时计算的。 - Naveen
5
请注意,在涉及可变长度数组(VLA)的情况下,那并不一定是正确的。 - caf
@caf:也许我会感到无助,但是......你所说的VLAs是什么意思?非常大的数组?哈哈 - Cory Gross
2
我想说的是,在函数 int foo(int n) { int a[n]; 中,sizeof a 的值不是在编译时计算的。 - caf
显示剩余2条评论
4个回答

42

sizeofstrlen()执行不同的操作。在这种情况下,您的声明

char string[] = "october";

是相同的。
char string[8] = "october";

编译器可以在编译时确定 string 的大小为 8。但是 strlen() 函数会在运行时计算字符串中字符的数量。所以,在调用 strcpy() 函数后,string 现在包含 "september"。 strlen() 计算出有 9 个字符。请注意,你没有为 string 分配足够的空间来容纳 "september",这将导致未定义行为。


是的,即使复制了“September”,它仍然给出了正确的字符串长度,尽管我们不知道第9个位置是否包含空字符! - Dr. Essen

1
输出结果是正确的,因为:
第一条语句中,字符串大小由编译器分配,即7+1(October有7个字节,加上一个空字符在编译时),
第二条语句中,你将9个字节的September复制到了8个字节的字符串中,
因此,你得到了September的大小为8个字节(但strlen()函数不适用于September,因为它没有空字符)。

3
字符串字面量"september"隐式包含空字符,因此如果程序尚未崩溃(由于写入超出string数组的末尾),则strlen()函数将起作用。 - Timothy Jones
@TimothyJones:这是未定义行为,因此从技术上讲,“崩溃”或“工作”之外还有其他选项。永远不要忽略鼻子恶魔的可能性。 - ShadowRanger

0

你的目标数组长度为8个字节("october"加上\0的长度),而你想在这个数组中放入9个字符。

man strcpy说: 如果strcpy()的目标字符串不够大,那么任何事情都可能发生。

请告诉我你真正想做什么,因为这听起来很糟糕。


1
这是一个用于理解sizeof()函数工作原理的测试程序。 - beparas

-1

在这个例子中,你必须消除缓冲区溢出问题。一种解决方法是使用strncpy函数:

memset(string, 0, sizeof(string));
strncpy(string, "september", sizeof(string)-1);

1
不,不,不。strncpy()虽然名字中带有“字符串”,但它并不是处理字符串的正确工具。在上面的例子中,由于没有任何一个元素包含零终止符,所以生成的string将不会是一个字符串 - pmg
它不是用于字符串的正确工具,因为它没有考虑到每个字符串定义中存在的零终止符(strncpy() 的设计仅适用于......未终止的字符串)。确保有足够的空间并使用 strcpy()(或者,如果您可以使用 BSD 经典 API,则使用 strlcpy())。 - pmg
5
我这么看:无论是strcpy还是strncpy都存在漏洞:
  • strcpy没有考虑缓冲区溢出的情况。
  • strncpy没有考虑字符串终止符。 所以在我看来,使用哪个版本都不重要 - 在任何情况下,我们必须避免其中一个问题。
- Agnius Vasiliauskas
@AgniusVasiliauskas:旧标准,但丑陋/啰嗦的解决方案是使用snprintf,它可以写入最多n - 1个字符,并始终以NUL结尾。或者,如果您能够使用C11,则可以使用strcpy_s - ShadowRanger

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