今天遇到了一个问题,在程序运行到某处总会报访问到错误的地址的错误,而且每次报错的堆栈还都不一样,排查了一段时间,发现是memcpy这里出了错
char *d = new char[data.size() * 4]; memset(d, 0, data.size() * 4); memcpy(d,temp_content.c_str(), temp_content.size());
这里乍一看没什么问题,但是如果这里data字符串为空而temp_content不为空的话,memcpy这样调用就出现了错误。
虽然暂时不会报错,因为这里通过new char[0]申请到了一个内存地址的指针(这里虽然为0但至少应该申请到了1块),这样memset不会报错,即使memset(d, 0, 1000);大概率也不会报错,只要后面的这块连续的内存没被别人占用
所以memcpy(d,temp_content.c_str(), temp_content.size());这种向未申请的内存中写数据也不会报错,但是这样的操作会破坏未申请内存的数据结构,当下一次别的操作申请内存时,申请到被破坏的内存,程序就会报错崩溃了(程序是不会关心你这个指针用的内存属不属于自己,只会关心你有没有用别人的内存!!!)
最好用memcpy_s代替!
delete 和 delete []的真正区别
这个和上面的问题有一点关联度,就是malloc 和 new的时候需要指定申请内存的大小,为什么free和delete时不需要呢?
先解释delete和delete[]的区别,他们同样都会释放指针所指向的内存空间,但如果指针类型不是基本数据结构时,delete只会调用第一个数组内的析构函数,其他的数组成员的析构函数都不会被调用!!!
第二个问题的答案
在学内存分配的问题的时候,malloc和calloc都要指定需要分配内存的大小,但是free的就不需要,我就纳闷free是咋知道从指针地址开始的多少长度是被分配了的?
当时就想,在malloc或者calloc的时候,编译器应该把大小的数值放到哪个地方了,当free的时候就去找那个数值,释放掉数值大小的堆空间。
但是到底放哪呢?
前几天在网上一阵乱逛,说是现代编译器就是把大小的数值放在分配地址开始的之前位置,但是具体在之前多少位置呢?今天在vs的内存监视器里面看到了。
测试代码如下:
[cpp]
#include "stdlib.h"
#include "stdio.h"
#define Num 100
int main(void)
{
int i;
int *p=(int *)malloc(Num);
for (i=0;i<Num;i++)
{
*(p+i)=1; //赋值为1只是为了看起来方便
}
free(p);
return 0;
}
其中p的地址为0x00393220
接着打开vs2008的内存监视器窗口看:
有一个地址为0x00393210的很可疑,因为0x64=100
那么改一下看看:
[cpp]
#define Num 50
再看内存监视器:
看到*(0x00393210)=0x32;即0x32=50
那应该就是把大小放这里了,就是说距离分配地址0x10之前的位置。
从中可以看出为什么分配堆更号内存大小(当然它的主要方面还是“碎片”的产生)的一个小方面~~~