2010-04-15 96 views
8

爲什麼下面的代碼導致分段錯誤? (我試圖創建一個同樣大小的兩個矩陣,一個靜態和其他與動態分配)C中矩陣的內存分配

#include <stdio.h> 
#include <stdlib.h> 

//Segmentation fault! 
int main(){ 
    #define X 5000 
    #define Y 6000 

    int i; 
    int a[X][Y]; 

    int** b = (int**) malloc(sizeof(int*) * X); 
    for(i=0; i<X; i++){ 
     b[i] = malloc (sizeof(int) * Y); 
    } 
} 

古怪的是,如果我註釋掉矩陣定義之一,代碼運行正常。就像這樣:

#include <stdio.h> 
#include <stdlib.h> 

//No Segmentation fault! 
int main(){ 
    #define X 5000 
    #define Y 6000 

    int i; 
    //int a[X][Y]; 

    int** b = (int**) malloc(sizeof(int*) * X); 
    for(i=0; i<X; i++){ 
     b[i] = malloc (sizeof(int) * Y); 
    } 
} 

#include <stdio.h> 
#include <stdlib.h> 

//No Segmentation fault! 
int main(){ 
    #define X 5000 
    #define Y 6000 

    int i; 
    int a[X][Y]; 

    //int** b = (int**) malloc(sizeof(int*) * X); 
    //for(i=0; i<X; i++){ 
    // b[i] = malloc (sizeof(int) * Y); 
    //} 
} 

我是一個32位的機器上運行GCC在Linux上。

編輯:檢查是否的malloc()成功:

#include <stdio.h> 
#include <stdlib.h> 

//No Segmentation fault! 
int main(){ 
    #define X 5000 
    #define Y 6000 

    int i; 
    int a[X][Y]; 

    int* tmp; 
    int** b = (int**) malloc(sizeof(int*) * X); 
    if(!b){ 
     printf("Error on first malloc.\n"); 
    } 
    else{ 
     for(i=0; i<X; i++){   
      tmp = malloc (sizeof(int) * Y); 
      if(tmp) 
       b[i] = tmp; 
      else{ 
       printf("Error on second malloc, i=%d.\n", i); 
       return; 
      } 
     } 
    }  
} 

什麼也沒有打印出來,當我運行它(當然期待爲 「段錯誤」)

+0

嘗試'fprintf'到'stderr'。 'printf'打印到'stdout',它被緩衝,所以如果程序崩潰了,你可能會失去輸出。 – 2010-04-15 15:50:14

+0

你還可以打印出我看看在失敗之前進入循環多遠? – 2010-04-15 15:56:45

回答

2

您正在收到分段錯誤,這意味着您的程序試圖訪問尚未分配給其進程的內存地址。數組a是一個局部變量,因此從堆棧分配內存。由於unwind指出a需要120兆字節的存儲空間。這幾乎肯定大於操作系統分配給您的進程的堆棧空間。只要for循環離開堆棧的末尾,就會出現分段錯誤。

在Linux中的堆棧大小由操作系統控制,沒有編譯器,請嘗試以下操作: -

$ ulimit -a 

在響應中,你應該看到一行是這樣的: -

stack size (kbytes)   (-s) 10240 

這意味着每個進程都可以獲得10Mbyte的存儲空間,遠遠不夠您的大型陣列。

您可以使用ulimit -s <stack size>命令調整堆棧大小,但我懷疑它不會允許您選擇120Mbyte堆棧大小!

最簡單的方法是使a爲全局變量而不是局部變量。

+0

使'a'成爲一個全局變量的確有訣竅。謝謝! (我正在研究的真正的程序實際上比這個玩具的例子複雜得多,但同樣的原則適用,所以現在我想我可以回到它了)。 – Snogzvwtr 2010-04-15 18:51:05

1

這些都是相當大的分配。你有沒有試過檢查以確保malloc()成功?

您可能會對所有陣列使用malloc(),並檢查每次是否成功。

6

您的a變量在32位系統上需要5000 * 6000 * 4 = 120 MB的堆棧空間。這可能會違反某些限制,從而導致分段錯誤。

此外,當然有可能malloc()在某些時候失敗,這可能導致您取消引用NULL指針。

+0

我雖然那樣,但我仍然無法用第三代碼工作,如果是這樣的話。 無論如何,我試圖檢查malloc()的結果,顯然他們都成功了。 – Snogzvwtr 2010-04-15 15:29:13

0

你的第三個代碼也不能用(至少在我的系統上)。

試着將內存分配給堆上的數組a而不是(當尺寸很大時)。

2

嘗試增加堆和棧限制在GCC:

gcc -Wl,--stack=xxxxx -Wl,--heap=yyyyy 
+0

嘗試過,但得到了「無法識別的選項」 - 堆棧「」。 從我檢查,顯然,這些選項只適用於Windows。我在Linux上。 – Snogzvwtr 2010-04-15 15:30:13

+0

實際上,在Linux中,這些選項僅適用於i386 PE目標。 – Juliano 2010-04-15 16:52:22

0

兩個矩陣不適合在你的記憶的極限。您一次只能分配一個。

如果您將Y定義爲3000而不是6000,那麼您的程序不應該發出段錯誤。

+0

我確實有(多)超過120MB的可用內存。一定有辦法做到這一點。 (實際上,我在我的實際程序中需要的矩陣甚至更大 - 這只是一個玩具示例,可以幫助找出問題所在)。 – Snogzvwtr 2010-04-15 15:36:32

1

堆棧溢出(如何恰當!)可能導致出現分段錯誤,這是您看到的。

在第三種情況下,堆棧指針正被移動到一個無效地址,但是因爲程序退出,所以沒有被用於任何事情。如果你在堆棧分配後進行了任何操作,你應該得到一個段錯誤。

1

也許編譯器只是將堆棧指針更改爲一些大的值,但從不使用它,因此從不導致內存訪問衝突。

嘗試在第三個例子中初始化A的所有元素?你的第一個例子試圖在堆棧中的A之後分配B,並且訪問高的堆棧(在第一次分配給B時)可能是導致段錯誤的原因。

+0

謝謝,我想現在我明白了這個問題。我之前並沒有意識到在爲這個堆棧分配足夠的空間之後訪問堆棧(創建b)*會導致段錯誤。 – Snogzvwtr 2010-04-15 18:46:46