0

可能重复:
为什么我写超出数组末尾时不会出现分段错误?

当我意识到发生了一些奇怪的事情时,我只是在玩指针。我知道,每当我们想使用strcpy将字符串src复制到另一个字符串dst时,我们应该为src分配所需的空间。

    char *dst,*src = "asdlskafksdhfklshfkshdkfhksdhfçsahdflçsdhfçklshadfç";

    dst = (char*)malloc(1); //only one char allocated
    strcpy(dst,src);

    printf("dst=%s.\n",dst);

此代码不应执行。然而,这并没有发生。代码执行,成功地将src复制到dst并像魅力一样打印dst 。有人可以解释一下为什么会这样吗?

4

4 回答 4

2

C 的部分性能是它没有太多内置错误检查的方式。众所周知,它传递了一个strcpy正确类型的指针,它不知道它指向了多少分配的内存。生成的机器代码只是从 src 指针读取到第一个空字节,然后将其粘贴到 dst 指针中。如果它没有覆盖其他人的内存,则没有错误。

什么是“别人的记忆”?通常,进程以为单位分配内存。当您 malloc 一个字节时,该进程将获得一整页内存,可能是几千字节,以便根据需要进行切片和切块。当您的进程试图在其分配的页面之外进行写入时,以及出于其他原因,就会发生分段错误。该错误通常由执行内存管理的操作系统和/或硬件生成。由于 src 只有几十个字节,因此不太可能走出进程页面。如果您使 src 成为更长的字符串,您可能会得到您期望的段错误。

有各种用于调试的 malloc 包装库,它们通过各种技巧使 C 检查内存错误。 ValgrindElectric Fence是其中最著名的。

PS 我对这些东西的工作原理有点模糊,但它比“它是未定义的行为”更令人满意。请随时编辑我的解释不足的地方。

于 2012-10-11T22:21:19.840 回答
2

您的字符串是在堆上分配的。堆的大小不是只有 1 个字节,而是大约 4kb 物理 RAM(默认 Windows 控制台应用程序大小)。

只有在尝试写入堆外的内存区域时才会出现分段错误。但是,您可能会破坏应用程序其他部分的内存。但是由于您的程序很小,并且在写入超出分配的内存后立即终止,因此您不太可能看到任何错误

于 2012-10-11T22:25:51.303 回答
1

在发布版本中,*dst 指向进程地址空间中的一些内存——你写入它,如果它碰巧被像你的应用程序这样有用的东西占用,它会崩溃。

在调试版本中,您的编译器可能会将 *dst 设置为 0 或一些可识别的值,例如 0xDEADBEEF,以便您可以发现这一点。

于 2012-10-11T22:16:07.937 回答
1

如果您在分配的内存之外写入结果是不确定的。如果你很幸运,你会得到一个段错误。如果你不走运,其他变量会被覆盖。底线:任何事情都会发生!

于 2012-10-11T22:17:46.403 回答