C++;堆栈和堆损坏 我最近在阅读C&C++中的堆栈和堆损坏。该网站的作者使用以下示例演示堆栈损坏 #include<stdio.h> int main(void) { int b = 10; int a[3]; a[0] = 1; a[1] = 2; a[2] = 3; printf(" b = %d \n",b); a[3] = 12; // oops it is invalid, behaviour is undefined printf(" b = %d \n",b); printf("address of b= %x\n",&b); printf("address of a[3]= %x\n",&a[3]); return 0; }

C++;堆栈和堆损坏 我最近在阅读C&C++中的堆栈和堆损坏。该网站的作者使用以下示例演示堆栈损坏 #include<stdio.h> int main(void) { int b = 10; int a[3]; a[0] = 1; a[1] = 2; a[2] = 3; printf(" b = %d \n",b); a[3] = 12; // oops it is invalid, behaviour is undefined printf(" b = %d \n",b); printf("address of b= %x\n",&b); printf("address of a[3]= %x\n",&a[3]); return 0; },c++,heap-corruption,stack-corruption,C++,Heap Corruption,Stack Corruption,当上述代码片段执行时,VC++在运行时显示堆损坏错误 这是未定义的行为。如果你做了“禁止”的事情,你不知道会发生什么。你不能保证你的程序能正常运行。C++和C都没有数组边界溢出或下溢检查。但是,您可以抽象出来,您可以使用重载索引运算符(运算符[])定义一个数组,您可以在其中检查数组索引是否超出范围并相应地执行操作。使用delete ptr删除指针时(通过new分配ptr时),之前分配的空间将返回到堆空间,但指针的值与之前相同。那么它,;这是一个很好的编程实践,即删除后应将ptr设置为NULL,例

当上述代码片段执行时,VC++在运行时显示堆损坏错误

这是未定义的行为。如果你做了“禁止”的事情,你不知道会发生什么。你不能保证你的程序能正常运行。

C++和C都没有数组边界溢出或下溢检查。但是,您可以抽象出来,您可以使用重载索引运算符(运算符[])定义一个数组,您可以在其中检查数组索引是否超出范围并相应地执行操作。使用delete ptr删除指针时(通过new分配ptr时),之前分配的空间将返回到堆空间,但指针的值与之前相同。那么它,;这是一个很好的编程实践,即删除后应将ptr设置为NULL,例如

int* p=new int();
...
if (p) {
  delete p;
  p = (int *) NULL;
}
// double deletion is prevented, and ptr us not dangling any more 
if (p) {
  delete p;
  p = (int *) NULL;
}

但是,堆栈或堆损坏(如果有的话)仅限于程序空间,并且当程序正常或异常终止时,所有占用的内存都会释放回操作系统

您必须小心此处的术语。堆栈是否会在程序的剩余生命周期中“损坏”?可能是,;可能不是。在本例中,您只损坏了当前堆栈帧中的数据,因此一旦退出该函数调用,实际上您的“损坏”将消失

但这还不是全部。既然您已经用不应该存在的字节覆盖了一个变量,那么会对您的程序产生什么连锁反应呢?如果您通过网络连接发送此数据,并且数据不再是预期的形式,则此内存损坏的后果可能会在逻辑上传递给其他函数作用域,甚至其他计算机。(通常,您的数据协议将内置安全功能,以检测和丢弃意外形式的数据;但这取决于您。)

堆损坏也是如此。每当您覆盖不应被覆盖的内容的字节时,以及每当您使用任意或不可知的数据进行覆盖时,您都会面临潜在灾难性后果的风险,这种后果在逻辑上可能会持续到程序的生命周期之外

<>在C++语言的范围内,这种条件概括为一个特定的短语:未定义行为。它表明,在你破坏了你的记忆之后,你根本不能依赖任何东西。一旦你调用了UB,所有的赌注都输掉了


在实践中,您通常有一个保证,即您的操作系统不允许您直接覆盖任何不属于您的程序的内存。也就是说,破坏其他进程或操作系统本身的内存是非常困难的。现代OSs的内存模型是特意设计的,目的是保持程序的隔离,防止程序和/或病毒的破坏。

一旦程序调用未定义的行为。它会被污染,直到它终止。你会得到技术上的答案,但也许你想要一个简单的答案。一旦您的程序遇到堆栈或堆损坏,就很糟糕了。你不能再相信它能起作用了。与其他错误(如无法读取文件)不同,堆栈或堆损坏在已发布的代码中绝不是可以容忍的错误。@NeilKirk:所以我的堆栈和堆现在无法工作?@meet不能信任它们工作。如果堆栈或堆损坏,则应终止、修复并重新启动程序。以允许更快的代码。其他语言针对许多常见错误执行背景检查,以帮助程序员,但这些都有开销。C和C++是在计算机比现在慢得多的时候发展起来的,速度是很重要的。但是你可以在C++中得到这些检查,它们只是可选的。使用
std::array
std::vector
代替C样式的数组和new和delete。他们为你提供更好的反腐败保护。尝试
std::向量a(3);a[3]=4并查看发生了什么。您的意思是堆栈在生命周期内没有损坏。不是吗?我的意思是:你不知道会发生什么。您的程序可能会继续无缝工作。但它可能会以你无法想象的最难以想象的方式崩溃。但是它也可能立即崩溃。好吧,当
delete
在arg中获取
NULL
时,它什么也不做。
int* p=new int();
...
if (p) {
  delete p;
  p = (int *) NULL;
}
// double deletion is prevented, and ptr us not dangling any more 
if (p) {
  delete p;
  p = (int *) NULL;
}