calloc/malloc/realloc有什麼不同?
C語言內存分配,有這麼三種:calloc/malloc/realloc(至少,其它的,比如mmap就先不管了)。那麼,這三種有什麼不同?現在使用還需要區服這些么?如果不需要區分,當初為啥要有這三種呢?如果需要區分,那麼使用場景是什麼?
- calloc - cppreference.com 分配內存、把內存清零。
- malloc - cppreference.com 分配內存、不把內存清零。
- realloc - cppreference.com 重新分配內存,把之前的數據搬到新內存去。
realloc(NULL, size) 等價於 malloc(size)。
calloc(num, size) 基本上等於 void *p = malloc(num * size); memset(p, 0, num * size); 但理論上 calloc 的實現可避免 num * size 溢出,當溢出時返回 NULL 代表失敗,而 malloc(num * size) 可能會分配了一個尺寸溢出後的內存。
注意不要把 realloc(ptr, 0) 當作 free(ptr),雖然在 VC 是等價的(realloc),但 C/C++ 標準說這是由實現定義的。man
calloc (3), 堆上分配內存,初始化0malloc (3), 堆上分配內存realloc (3), 重新分配堆上內存
APUETCPLrealloc - cppreference.com
malloc - cppreference.com
calloc - cppreference.com我來補充一個malloc在Linux上(其他系統上沒有驗證)的特性吧。
當malloc需要分配內存大小超過512KB(32位系統)或4*sizeof(long)MB(64位系統)時,所分配的內存區域一定會被全0填充。此時,再通過memset全0填充就浪費時間了。原因如下
在Linux上,glibc的這些內存分配函數對大內存的分配和小內存的分配採取完全不同的兩種行為。當分配內存較小時,內存分配函數在堆上分配內存。此時,堆內存可能在之前被使用過,所以你得到的內存區域可能含有雜亂的數據。
但是當分配內存較大時,這些函數直接通過mmap系統調用進行內存映射。這時,操作系統處於安全考慮,會強制全0填充這塊內存。所以你得到的內存區域一定是全0填充過的。函數通過與mallopt的M_MMAP_THRESHOLD選項進行比較,判定你要分配大內存塊還是小內存塊。
你可以通過mallopt()或環境變數來設置M_MMAP_THRESHOLD,默認值是128KB。它的大小不會超過DEFAULT_MMAP_THRESHOLD_MAX。
DEFAULT_MMAP_THRESHOLD_MAX在32位系統上是512KB,在64位系統上是4*sizeof(long) MB。以上malloc提供的堆內存是未初始化的,複雜度可以視為O(1),
calloc本質上是調用了malloc,然後將內存「初始化」為0,複雜度是O(n);由於調用malloc時需要提早知道內存塊的大小,所以當遇到無法提早知道數組長度的問題時,就需要這樣操作來調整數組大小:1. 創建新的數組;2. 從舊的數組中複製元素到新的數組;3. free舊的數組.// my_array has a length of 100
int *my_array = malloc(100 * sizeof(int));
// stuff happens...
// oops, my_array now needs to have a length of 101
int *old = my_array;
my_array = malloc(101 * sizeof(int));
for (int i=0; i &< 100; ++i) {
my_array[i] = old[i];
}
free(old);
我最常用malloc和realloc。
calloc等於malloc加memset,不過建議分開寫,以降低他人閱讀成本。
realloc我一般用於自增長的內存空間,類似c++ vector的那種增長。
realloc一定要注意返回值判空,否則會造成內存泄漏。c庫有些api正交性不好,都是歷史原因吧。這個問題完全可以上網查,不必來此提問。自己動手, 豐衣足食
推薦閱讀:
※所有遞歸都可以改寫成循環嗎?
※如何評價「消逝的光芒」這款遊戲 ?
※使用「天河二號」超級計算機玩遊戲會是什麼感覺?
※計算機專業女孩子應該往什麼方向發展?
※野指針危害真的很大嗎?