2016-05-26 54 views
5

我主要感興趣的是收縮這樣一個數組的生存能力。在動態分配的二維數組上使用realloc()是個好主意嗎?

我正在使用單個malloc()調用來創建個別中等大小的2D數組的項目。 (每個數組最多隻有幾十個MiB)。事情是,在其中一個陣列的整個生命週期中,其內容的大小會急劇縮小(超過一半)。很明顯,我可以在程序的整個生命週期內保留數組大小。 (這只是一個x MiB在一個帶有可用RAM的GiB的系統上)。但是,在程序終止之前,我們正在談論的是超過一半的分配空間被濫用,並且由於我的性質使用該數組,所有幸存的數據保存在連續的一組行中(在塊的開始處)。如果我真的不需要它,保留所有RAM似乎是一種浪費。

雖然我知道realloc()可以用來收縮動態創建的數組,但2D數組​​更復雜。我認爲我理解它的內存佈局(因爲我實現了構建它的函數),但是這推動了我對語言和編譯器工作的理解的極限。顯然,我將不得不使用行(並處理行指針),而不僅僅是字節,但我不知道這一切的結果會是多麼可預測。

而且,是的,我需要用一個malloc()創建數組。有問題的對象有幾百萬行。我試着用malloc()分別循環每行,但程序總是凍結在10萬個malloc()。

對於背景,我使用的構建這些陣列源如下:

char ** alloc_2d_arr(int cnum, int rnum) { 
     /* ((bytes for row pointers + (bytes for data)) */ 
     char **mtx = malloc(rnum * sizeof (char *) + rnum * cnum * sizeof (char)); 

     /* Initialize each row pointer to the first cell of its row */ 
     char *p = (char *) (mtx + rnum); 
     for (int i = 0; i < rnum; i++) { 
       mtx[i] = p + i * cnum; 
     } 

     return mtx; 
} 
+2

'realloc'對於這樣的大桌不是一個好主意,請看看「avl」和「red-black」樹。 –

+1

「如果我真的不需要它,保留所有內存似乎是一種浪費。」 - 首先*個人資料*。其次,realloc會觸發將所有靜態內部數據複製到不同頁面的高風險,您承擔的非平凡費用僅僅是因爲試圖保存自己聲稱的ram而不是真正的問題。這裏唯一的勝利場景是'realloc'保持與你的內存基地相同的區域頭部,並且尾部頁面被返回用於其他用途;一些'realloc'沒有關於...的保證。 – WhozCraig

+0

...所以你有沒有考慮過只是做2(或3或4,不管)分配,記住你最終保留的是哪一個,'free()' - 一旦事件發生,你不再需要的那些?即你的矩陣的「保留」一半在第一個分配中,下半部分在另一個分配中,最終你可以釋放下半部分。 – WhozCraig

回答

2

使用多維數組,這可以使用或不指向可變長度數組來完成。既然你可能不想分配任何額外的內存,這將會做到位。

首先分配一個20由10陣列:

int (*array)[10] = malloc(sizeof(int) * 20 * 10); 
for(size_t i = 0 ; i < 20 ; i++) 
    for(size_t j = 0 ; j < 10 ; j++) 
      array[i][j] = i * 100 + j; 

如果要更改的行數,沒有元素必須被移動,所以只需要一個 realloc的。將行數更改爲15並不重要:

array = realloc(array , sizeof(int) * 15 * 10); 

如果要更改列計數,則必須移動元素。由於我們不需要複製第一列,所以複製從第二列開始。函數memmove用於避免內存重疊,在這種情況下不會發生,但如果新列數更大,則可能會發生。它也避免了混疊問題。請注意,這段代碼的定義只是因爲我們正在使用分配的內存。讓我們來改變列數到3:

int (*newarray)[3] = (int(*)[3])array; 
for(size_t j = 1 ; j < 15 ; j++) 
    memmove(newarray[j] , array[j] , sizeof(int) * 3); 
newarray = realloc(array , sizeof(int) * 15 * 3); 

工作例如:https://ideone.com/JMdJO0

如果新的列數恰好是比舊的更大,那麼內存就必須先重新分配(只是獲得更多空間),然後列複製將發生,而從最後一列開始。

+0

它讓我難以承認,但我無法理解'int(* array)[10] = malloc(...);'。基於我對C的明顯缺乏把握,這看起來像是初始化一個新創建的變量,並將一個取消引用的指針作爲其標識符。解除引用三重指針(兩次)並給出malloc()輸出是一回事,但在前面放置一個類型使得它看起來像是一個RAM地址被用作符號(這沒有意義) 。我感覺我在學習C時看到了什麼,但是用Google搜索相關詞彙顯然給出了污染結果。 – CircleSquared

+0

@CircleSquared它是一個指向多維數組的指針。在我的例子中有兩個維度。像這樣:'int a [7] [9]; int(* pa)[9] = a;',除了在我的例子中,我不指向指向自動數組的指針,而是指向分配的內存。 – 2501

+0

謝謝你向我展示一個更有效的方法來動態分配多維數組** **以簡單回答我的問題。 *因此,它足夠安全,但這是設置陣列的更好方法。* – CircleSquared