目录
前言
今日在NK网练题,题意为求特殊的倒置字符串,当使用纯C写题解时用到了动态字符数组存储字符串,因为编译器的原因不支持变长数组,所以选用堆区创建动态数组方法解决,但是运行一切正常后加入释放内存模块内容,出现了令人迷惑的 HEAP CORRUPTION DETECTED 异常,经过学习总结,完善个人代码无误后,写出此文,以警醒自身、加深印象。
题目直达链接:倒置字符串
一、问题描述
当我们尝试释放堆区内存时,出现如下问题:
二、原因说明
该问题发生于操作堆内存的时候。产生该问题的原因是:你实际使用的内存大小超出了你实际申请的内存大小,在释放内存的时候就会发生该问题。
三、问题案例
首先我们方便C/C++使用者的日常习惯,给出两种风格的函数,其作用都是返回动态分配的内存,函数实现如下:
int* use_ptr_c(int n)
{
return (int*)malloc(n * sizeof(int));
}
int* use_ptr_cplusplus(int n)
{
return new int[n];
}
给出调用上面两功能的测试函数:
void test()
{
int* arr1 = use_ptr_c(10);
int* arr2 = use_ptr_cplusplus(10);
// 赋值操作
for(int i = 0;i < 10;i++)
{
arr1[i] = i * i;
arr2[i] = i * i;
}
// 打印内容
for(int j = 0;j < 10;j++)
{
printf("%d\t", arr1[j]);
}
printf("\n");
for (int j = 0; j < 10; j++)
{
printf("%d\t", arr2[j]);
}
printf("\n");
// 释放内存操作
free(arr1);
arr1 = NULL;
delete[] arr2;
arr2 = nullptr;
}
运行结果:
接着稍加改动代码,呈现如下:
void test()
{
int* arr1 = use_ptr_c(10);
int* arr2 = use_ptr_cplusplus(10);
for(int i = 0;i <= 10;i++)
{
arr1[i] = i * i;
arr2[i] = i * i;
}
for(int j = 0;j < 10;j++)
{
printf("%d\t", arr1[j]);
}
printf("\n");
for (int j = 0; j < 10; j++)
{
printf("%d\t", arr2[j]);
}
printf("\n");
free(arr1);
arr1 = NULL;
delete[] arr2;
arr2 = nullptr;
}
仔细找不同,发现我们在对堆区数组进行赋值操作时发生了越界访问,对arr1/2[n]元素进行了赋值操作,所以此后当你在释放arr1和arr2指向的内存时,由于你使用了超过申请大小的内存空间,导致内存不能正确释放,就会发生上面的问题。
试着运行:
不变的味道,果然发生了HEAP CORRUPTION DETECTED异常,那么可能又会想,如果把堆内存释放交给程序垃圾处理模块自动回收,还会发生这样的报错吗?
可以看到并没有弹出异常窗口,通过内存泄漏检测工具(VLD),看到有两处内存泄露点,仅仅因为没有对应free和delete对应内存,并非堆区异常。
总结
当实际使用的内存大小超过了申请内存空间大小时,在以后释放内存的时候就会引发HEAP CORRUPTION DETECTED:after Normal block错误。
解决方案:当申请堆内存空间的时候,申请的空间大小一定要大于等于实际上使用的内存空间大小。