1. 程式人生 > >由memcpy記憶體越界引發的問題 && delete 和 delete []的真正區別

由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之前的位置。

從中可以看出為什麼分配堆更號記憶體大小(當然它的主要方面還是“碎片”的產生)的一個小方面~~~