【问题标题】:Sizeof vs StrlenSizeof vs Strlen
【发布时间】:2012-04-13 19:07:11
【问题描述】:
#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

我的语法有什么问题吗?

【问题讨论】:

  • 您正在写超出数组 string 的末尾。这是未定义的行为。 string 只能包含 8 个字符(7 个用于“october”,1 个用于空终止符)。当您调用 strcpy 时,您正在向其写入 10 个字符(9 代表“九月”,1 代表空终止符),这意味着您已经超过了数组的末尾并正在覆盖相邻的内存。
  • 请注意,sizeof 是在 编译 时计算的,而 strlen 是运行时。
  • @Naveen:请注意,在涉及 VLA 的情况下,这不一定是正确的。
  • @caf:也许我会觉得一无所知,但是.....你说的 VLA 是什么意思?非常大的数组?大声笑
  • 我是说在函数int foo(int n) { int a[n]; 的值sizeof a 不是在编译时计算的。

标签: c sizeof strlen


【解决方案1】:

sizeofstrlen() 做不同的事情。在这种情况下,您的声明

char string[] = "october";

一样
char string[8] = "october";

因此编译器可以判断string 的大小为8。它在编译时执行此操作。

但是,strlen() 在运行时计算字符串中的字符数。所以,在你调用strcpy() 之后,string 现在包含“september”。 strlen() 计算字符并找到其中的 9 个。请注意,您没有为string 分配足够的空间来保存“九月”。这是未定义的行为。

【讨论】:

  • 是的,即使在复制“September”之后,它仍然给出正确的字符串长度,尽管我们不知道第 9 位是否包含空字符!
【解决方案2】:

输出是正确的,因为

编译器分配的第一个语句字符串大小为 7+1(10 月为 7 个字节,编译时空终止符为 1 个字节)

第二个语句:你是在复制九月(9字节到8字节字符串);

9 月的大小为 8 个字节(strlen() 仍然无法在 9 月工作,它没有空字符)

【讨论】:

  • 字符串文字 "september" 隐含地包含空字符,因此如果程序尚未崩溃,strlen() 将起作用(由于写入超过 string 数组的末尾)
  • @TimothyJones:这是未定义的行为,所以从技术上讲,除了“崩溃”或“工作”之外,还有其他选项。永远不要忽视鼻恶魔的可能性。
【解决方案3】:

您的目标数组是 8 个字节(“october”加上 \0 的长度)并且您想在该数组中放入 9 个字符。

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

请告诉我你真正想做什么,因为这闻起来很臭

【讨论】:

  • 这是理解 sizeof() 工作原理的测试程序
【解决方案4】:

您必须消除此示例中的buffer overflow 问题。一种方法是使用strncpy:

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

【讨论】:

  • 不,不,不。 strncpy(),尽管它的名字,是用 strings 做任何事情的错误工具。在上面的示例中,生成的 string 将不是 字符串,因为它的 8 个元素中没有一个包含零终止符。
  • 这对字符串来说是错误的工具,因为它没有考虑到定义中存在于每个字符串中的零终止符(strncpy() 设计使其仅对 ... errr .. . 未终止的字符串)。确保您有空间并使用strcpy()(或者,如果您可以使用BSD-isms,请使用strlcpy())。
  • 我看到类似这样的情况:strcpystrncpy 都有漏洞:-strcpy 不考虑缓冲区溢出。 - strncpy 不考虑字符串终止符。所以在我看来,我们将使用哪个版本并不重要——无论如何我们必须避免一个问题或另一个问题......
  • @AgniusVasiliauskas:旧标准,但丑陋/冗长,解决方案是using snprintf,最多可写入n - 1 个字符,并且始终以NUL 终止。或者,如果您能够使用 C11,strcpy_s
猜你喜欢
  • 1970-01-01
  • 2013-02-19
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
  • 2010-12-25
  • 1970-01-01
  • 2017-12-01
  • 1970-01-01
相关资源
最近更新 更多