我遇到了一个我不明白的问题,以下是我的代码:
#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(格式)是4个字节而在另一台机器上,sizeof(格式)是8个字节; (在两台机器上, char 只需要一个字节,这意味着 sizeof(* format)等于1)
然而,无论在哪台机器上,结果仍然让我感到困惑。因为即使对于第二台机器,分配的内存仅为20 + 8,即28字节,显然该字符串的长度为33,这意味着至少需要 33字节。但运行此程序后出现 NO分段错误。正如您所看到的,即使我试图取消引用位置40处的推理,该程序也不会崩溃并显示任何段错误信息。
任何人都可以帮忙解释原因吗?非常感谢你。
答案 0 :(得分:2)
访问未分配的内存是未定义的行为,这意味着您可能会遇到段错(如果您很幸运),或者您可能没有。
或者您的程序可以在屏幕上自由显示小猫。
猜测为什么在未定义的行为中发生或不发生的事情通常会适得其反,但我想你发生的事情是操作系统实际上为你的应用程序分配了比它要求的更大的内存块。由于您的应用程序并未尝试取消引用该较大块之外的任何内容,因此操作系统不会检测到该问题,因此不会因分段错误而终止您的程序。
答案 1 :(得分:1)
因为未定义的未定义行为。它不是“定义为崩溃”。
答案 2 :(得分:1)
没有seg错误,因为没有理由存在错误。因为从堆中获取了内存,所以很可能会写入堆中,因此内存不是只读的。此外,那里的内存可能存在并为您(或至少是程序)分配,因此它不是访问冲突。通常你会得到一个seg错误,因为你可能试图访问没有给你的内存,或者你可能试图写入只读的内存。这些似乎都不是这种情况,所以没有错。
实际上,写入缓冲区的末尾是一个常见的安全问题,称为缓冲区溢出。这是一段时间内最常见的安全漏洞。如今人们正在使用更高级别的语言来检查索引范围,所以这不再是一个大问题了。
答案 3 :(得分: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/