[英]Difference between array type and array allocated with malloc
今天我正在幫助我的一個朋友編寫一些 C 代碼,我發現了一些奇怪的行為,我無法向他解釋為什么會發生這種情況。 我們有一個包含整數列表的 TSV 文件,每行一個int
。 第一行是列表的行數。
我們還有一個帶有非常簡單的“readfile”的 ac 文件。 第一行被讀取到n
,即行數,然后有一個初始化:
int list[n]
最后是一個帶有fscanf
的n
循環。
對於小 n(直到 ~100.000),一切都很好。 但是,我們發現當 n 很大(10^6)時,會發生段錯誤。
最后,我們將列表初始化更改為
int *list = malloc(n*sizeof(int))
一切順利,即使n
非常大。
有人可以解釋為什么會發生這種情況嗎? 是什么導致int list[n]
,當我們開始使用list = malloc(n*sizeof(int))
時停止了?
這里有幾個不同的部分在起作用。
第一個是將數組聲明為
int array[n];
和
int* array = malloc(n * sizeof(int));
在第一個版本中,您聲明了一個具有自動存儲持續時間的對象。 這意味着數組只有在調用它的函數存在時才存在。 在第二個版本中,您將獲得動態存儲持續時間的內存,這意味着它會一直存在,直到它被free
顯式釋放。
第二個版本在這里工作的原因是 C 通常如何編譯的實現細節。 通常,C 內存被分成幾個區域,包括堆棧(用於函數調用和局部變量)和堆(用於malloc
ed 對象)。 堆棧的大小通常比堆小得多; 通常它大約是 8MB。 因此,如果您嘗試分配一個巨大的數組
int array[n];
那么您可能會超出堆棧的存儲空間,從而導致段錯誤。 另一方面,堆通常有很大的大小(例如,系統上可用的空間一樣多),因此對大對象進行malloc
不會導致內存不足錯誤。
通常,要小心 C 中的可變長度數組。它們很容易超過堆棧大小。 首選malloc
除非您知道大小很小,或者您確實只需要很短的時間數組。
希望這可以幫助!
int list[n]
為堆棧上的n
整數分配空間,通常非常小。 在堆棧上使用內存比替代方案快得多,但它非常小,並且如果您執行諸如分配大數組或進行過深遞歸之類的操作,很容易使堆棧溢出(即分配太多內存)。 您不必手動釋放以這種方式分配的內存,這是由編譯器在數組超出范圍時完成的。
另一方面, malloc
在堆中分配空間,與堆棧相比,該空間通常非常大。 您將不得不在堆上分配更多的內存以耗盡它,但是在堆上分配內存比在堆棧上分配內存要慢得多,並且您必須在完成使用后通過free
手動釋放它它。
int list[n] 將數據存儲在堆棧中,而 malloc 將其存儲在堆中。
棧是有限的,沒有多少空間,而堆要大得多。
int list[n]
是一個 VLA,它在堆棧上而不是在堆上分配。 您不必釋放它(它會在函數調用結束時自動釋放)並且分配速度很快,但正如您所發現的,存儲空間非常有限。 您必須在堆上分配更大的值。
假設您的實現中有一個典型的實現,很可能是:
int list[n]
堆棧上的已分配列表,其中:
int *list = malloc(n*sizeof(int))
在堆上分配的內存。
在堆棧的情況下,它們可以增長的大小通常是有限的(如果它們可以增長的話)。 在堆的情況下仍然有一個限制,但這往往在很大程度上和(廣泛地)受您的 RAM+交換+地址空間的限制,通常至少要大一個數量級,如果不是更多。
如果您使用的是 linux,則可以將 ulimit -s 設置為更大的值,這也可能適用於堆棧分配。 在堆棧上分配內存時,該內存會一直保留到函數執行結束。 如果在堆上分配內存(使用 malloc),則可以隨時釋放內存(甚至在函數執行結束之前)。
通常,堆應該用於大內存分配。
當您使用malloc
分配時,內存是從堆分配的,而不是從堆棧分配的,堆棧的大小受到更多限制。
int array[n];
這是一個靜態分配數組的例子,在編譯時數組的大小是已知的。 並且該數組將在堆棧上分配。
int *array(malloc(sizeof(int)*n);
這是一個動態分配數組的例子,用戶在運行時就知道數組的大小。 並且該數組將在堆上分配。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.