数组内存分配概念
在這里解答一下:
int arr[4];
&arr[1] = arr[0] + sizeof(int) ;
靜態分配, 即普通數組, 由于在棧中分配, 而棧的生成方向是自高地址向低地址生成。 所以有:
&arr[0] > &arr[1] ....
動態分配的數組。針對動態數組。 動態數組的內存分配在heap中。 而heap 的生成是由低地址向高地址生成。 所以有:
&arr[0] < &arr[1] <...
這是我以為的。 ?答案是我我錯了。
測試一下:
[cpp] view plain copy print?結果如下:
為什么無論是靜態數組還是動態數組, 數組元素的分配都是對元素從低地址到高地址。?
無論動態還是靜態?地址都是arr[0]?<?arr[1]?也就是數組內存是統一分配的內部元素都是從低地址到高地址 。? ? ? ? ? ?
1、內存分配的三種方式:
1)、從靜態存儲區分配。數據的內存在程序編譯時已經被分配,該內存在整個運行期間長期駐留,不會被釋放;程序結束時,由操作系統自動釋放。這類數據包括靜態數據和全局數據。
2)、從棧空間分配。函數執行過程中,函數中的局部變量的內存,在棧上被分配;當函數調用完成后,隨函數的返回空間也被釋放。
3)、從堆空間分配。由開發者動態的申請內存,并手動的釋放內存。
本文具體介紹動態內存分配,C語言中采用malloc、recalloc等函數分配內存;c++中使用new操作符申請內存。
malloc函數的返回值為void*,調用該函數時,需要顯式的類型轉化。返回值表示內存空間的首地址。如果該地址為NULL,表示系統沒有滿足的內存可供分配。因此在使用該地址之前,必須判斷是否分配成功。例如:
int*p=(int*)malloc(sizeof(int)*10);
if(p != NULL)
{
......//使用該內存空間
}
在該內存使用完成后,需要開發者手動釋放該內存:free(p):
這里需要注意:1)、調用free后,p和所指向的內存地址被斷開,但是p的值仍然沒有變化,此時如果調用p,將會出現錯誤,這時p就是一個野指針;因此當free(p);之后,應該將p的值賦為NULL,以免p再次調用出現錯誤。2)、雖然內存已經分配完成,但是并沒有初始化,直接使用,取到的結果不正確。
4)、當malloc申請的內存不滿足用戶使用要求時,就需要重新分配內存,這時可以使用realloc函數。
void *realloc(void *memblock,size_t size ); memblock參數表示已經分配的內存地址的指針,即就是p;size參數表示需要分配的字節數
該函數的返回值為,重新分配的內存空間的首地址。
realloc函數,在malloc函數已經分配的內存基礎上再次擴充內存。realloc函數的返回值類型仍為void*。可以分三種情況來解釋realloc。
情況一:需要分配的內存空間小于已經分配的空間。
那么這時只是從原來已經分配的內存空間中,將多余的空間釋放,保留realloc函數需要的空間大小,將原來空間的的首地址賦值給realloc函數返回(這個地址和p的值是相同的);如果這樣做的,可能會導致數據出錯,因此一般不要縮小原內存空間;
情況二:需要分配的內存空間等于已經分配的空間。
將原來內存空間的首地址賦值給realloc函數返回;
情況三:需要分配的內存空間大于已經分配的空間。
1)如果原來的內存后,還有足夠的空間,滿足分配要求,那么直接在原來的內存的后面,分配適量的空間,并將原來空間的首地址賦值給realloc函數,返回;
2)如果原來內存后,沒有足量的內存空間,滿足分配要求,那么重新選擇一塊足量的空間分配,并將原來已經分配的空間的數據拷貝到新分配的內存中,將原指針p指向的空間釋放。將新分配的空間首地址賦值給realloc函數返回,因此對于原來的空間,realloc函數在分配內存時,已經釋放了原來的內存,不需要再次釋放,否則會出錯。
情況四:當分配的內存大小為0
系統是可以返回一個非NULL值,但是這個空間不能被使用。使用將會出錯,效果等同于free(p);
情況五:當原來的指針為NULL
這種情況,的作用就相當于直接調用malloc函數一樣;可以這樣理解,NULL說明原空間沒有分配成功,那么調用realloc函數,肯定需要分配一塊新的內存空間,這不就相當于直接調用了malloc函數。
情況六:如果realloc函數調用失敗
那么原來的空間地址不會被釋放,保留原來的內存,該內存空間可以正常使用。
綜上,在使用malloc函數時,需要注意幾點:1)調用malloc函數后,需要判斷內存是否分配成功;2)使用空間之前,需要給空間賦初始值;3)防止內存越界訪問;4)釋放內存空間之后free(p);,需要將原指針的值賦空(p=null;),以防再次使用產生錯誤,出現野指針;5)realloc函數對于原始的內存空間,在分配內存時已經做過處理,因此除realloc函數調用失敗外,其余情況不能再次釋放原空間內存,否則會出錯。
2、既然malloc和free已經可以分配內存了,為什么還要引入new和delete?
首先需要明白,malloc和free是c語言中的c庫函數,而new和delete是c++中的標識符;因此這兩組擁有不同的性質;
接著,malloc和free不僅可以使用在C語言中,也可以使用在c++語言中,但是new和delete只是c++中特有的屬性,在C語言中無法使用,因此new和delete有他的局限性;
再次,new和delete不僅需要分配內存空間,而且在面向對象的語言中,對于對象,還需要完成初始化,觸發對象的構造和析構,這些操作是malloc和free無法完成的(筆者就在曾經實現鏈表的過程中,在結構體定義時,將一個數組元素定義為string類型的,在使用malloc申請內存后,調用過程中無法給該元素賦值。從這個例子中可以看出雖然malloc和new分配的內存大小相等,但是具體的內存內部工作還是有區別的)。
最后,malloc在分配內存時,需要開發者手動的指定元素的大小,并且返回值需要顯式的類型轉化;但是new就不需要指定和轉化。
3、在c++中,既然new和delete可以完成所有分配的工作,為什么還要保留malloc和free?
這是因為c++編譯器為了兼容c編譯,是c中的所有函數可以在c++編譯器上正常使用,因此保留了malloc和free
總結
- 上一篇: 匈牙利命名法的优缺点
- 下一篇: 关于软件的架构设计