0

我遇到了一个我不明白的问题,以下是我的代码:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <cstdlib>
using namespace std;

int main(int argc, char **argv)
{
    char *format = "The sum of the two numbers is: %d";
    char *presult;
    int sum = 10;
    presult = (char *)calloc(sizeof(format) + 20, 1);   //allocate 24 bytes

    sprintf(presult, format, sum);  // after this operation, 
                                    // the length of presult is 33
    cout << presult << endl;

    presult[40] = 'g';   //still no segfault here...
    delete(presult);
}

我在不同的机器上编译了这段代码。在一台机器上,sizeof(format)是 4 个字节,而在另一台机器上,sizeof(format) 是 8 个字节;(在两台机器上,char只占用一个字节,这意味着sizeof(*format)等于 1)

但是,无论在哪台机器上,结果仍然让我感到困惑。因为即使对于第二台机器,分配的内存也只有 20 + 8 即 28 个字节,显然字符串的长度为 33,这意味着至少需要 33 个字节。但是在我运行这个程序后没有发生分段错误。如您所见,即使我尝试取消引用第 40 位的 presult,程序也不会崩溃并显示任何段错误信息。

谁能帮忙解释为什么?太感谢了。

4

4 回答 4

2

访问未分配的内存是未定义的行为,这意味着您可能会遇到段错误(如果幸运的话),也可能不会。

或者您的程序可以自由地在屏幕上显示小猫。

推测为什么在未定义的行为领域发生或不发生某些事情通常会适得其反,但我想发生在你身上的事情是操作系统实际上为你的应用程序分配了比它要求的更大的内存块。由于您的应用程序不会尝试取消引用该较大块之外的任何内容,因此操作系统不会检测到问题,因此不会因分段错误而终止您的程序。

于 2013-07-09T21:41:51.667 回答
1

没有段错误,因为没有理由存在一个。由于您从堆中获得了内存,因此您很可能仍在写入堆,因此内存不是只读的。此外,那里的内存可能存在并为您(或至少为程序)分配,因此这不是访问冲突。通常你会得到一个段错误,因为你可能试图访问没有给你的内存,或者你可能试图写入只读的内存。这些似乎都不是这里的情况,所以没有任何问题。

事实上,写入缓冲区末尾是一个常见的安全问题,称为缓冲区溢出。这是一段时间以来最常见的安全漏洞。现在人们正在使用更高级别的语言来检查索引范围之外,所以这不再是一个大问题了。

于 2013-07-09T21:54:17.163 回答
1

因为未定义的行为是未定义的。它不是“定义为崩溃”。

于 2013-07-09T21:42:31.470 回答
1

对此做出回应:“结果仍然让我感到困惑。因为即使对于第二台机器,分配的内存也只是 20 + 8 即 28 个字节,显然字符串的长度为 33,这意味着至少 33 个字节是需要的。”

sizeof(some_pointer) == sizeof(size_t) 在任何基础设施上。您在 32 位机器 (4B) 和 64 位机器 (8B) 上进行测试。

你必须给 malloc 分配的字节数;sizeof(ptr_to_char) 不会给你字符串的长度(直到 '\0' 的字符数)。

顺便说一句,strlen 做你想做的事:http ://www.cplusplus.com/reference/cstring/strlen/

于 2013-07-10T11:41:31.557 回答