由memcpy記憶體越界引發的問題 && delete 和 delete []的真正區別
今天遇到了一個問題,在程式執行到某處總會報訪問到錯誤的地址的錯誤,而且每次報錯的堆疊還都不一樣,排查了一段時間,發現是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之前的位置。
從中可以看出為什麼分配堆更號記憶體大小(當然它的主要方面還是“碎片”的產生)的一個小方面~~~