2011-04-18 54 views
0

這兩個函數都是(至少在我的編譯器下)保證會創建一個seg錯誤,但我不知道爲什麼。我真的很喜歡他們的功能,我也看到了類似的例子,所以我很想知道這裏出了什麼問題,或者怎麼做,我認爲這實際上是做什麼的,它將一個「級」傳遞給某個函數,然後能夠操縱其變量(例如lvl.lvl_cl [X] [Y] [Z] = some_number),然後傳遞迴用於進一步使用將結構傳遞給一個函數會創建一個默認錯誤

任何幫助理解:)

typedef struct { 
    int lvl_cl[500][500][50]; 
    char lvl_ch[500][500][50]; 
} level; 

level plugh(level * in_lvl){ 
    in_lvl->lvl_cl[444][444][44]++; //it segfaults even if this line is removed 
    return * in_lvl; 
} 

level foo(level inlvl){ 
    inlvl.lvl_cl[443][443][43]++; //it segfaults even if this line is removed 
    return inlvl; 
} 

int main(void){ 
    level world; 
    plugh(&world); 
    foo(world); 
    return 0; 
    } 
+0

12.000 KO值int。哇!閱讀您的評論。使用類似這樣的方式:將'level'定義爲'* level',並使用'new'關鍵字在堆上創建對象。它絕對會幫助你。 – 2011-04-18 19:54:11

+0

你知道你的結構沒有被初始化嗎? – 2011-04-18 20:03:53

+1

@AdrianMar這是一個C的問題。 – 2011-04-18 20:06:11

回答

0

每當您撥打foo函數時,它會複製整個world結構,它非常大。嘗試通過指針:

void foo(level *inlvl){ 
    inlvl->lvl_cl[443][443][43]++; 
} 
+0

好吧,它遠不止於此。 C沒有參考。即使他們做了,也有一個堆棧分配的結構實例。 – 2011-04-18 20:07:02

+0

當我嘗試編譯上述代碼之前,不能通過引用傳遞它是因爲它在'&'標記之前說的「...:錯誤:預計';',','或')' – Jacob 2011-04-18 20:17:52

+0

同意,改爲指針 – Elalfer 2011-04-18 20:18:49

3

堆棧溢出?

說真的,你有沒有考慮過你的結構有多大?如果將它存儲在堆棧中,它會溢出...

嘗試一個sizeof(level),看到實際大小會很有趣。

編輯:如果你需要的東西很大,你真的應該考慮你在哪裏以及如何存儲它。如果你將它傳遞給一個函數,你將製作一個拷貝的結構並將它放在堆棧中。如果你返回結構體,你很可能需要另一個堆棧副本。

你真的需要傳遞並返回結構嗎?如果沒有,你可以把它放在正常的靜態存儲器(一個普通的全局變量)或在堆上分配一個。無論哪種方式,如果傳遞一個指向它的指針,它只會佔用全部結構的一小部分。

+0

我的一半問題是我需要它那麼大......這實際上是來自世界[10] [1000] [1000] [1000] [100] [10] lol – Jacob 2011-04-18 19:53:16

+3

相信我,你不需要它那麼大。你需要使用malloc進行分配,以便堆放在堆上而不是堆棧中。 – 2011-04-18 19:57:16

+2

你確定*你需要一個大的數據結構嗎?你知道'int world [10] [1000] [1000] [1000] [100] [10]'有10萬億個元素,對嗎? – 2011-04-18 20:00:28

1

問題是,你在堆棧上放置了大約100MB,你的堆棧並不大。

您需要開始使用指向level結構和堆分配的指針,而不是試圖將其複製到堆棧中!

2

首先,這是存儲器的LOT:

500x500x50x1(因爲1個字節在炭)+ 500x500x50x4(因爲在一個int 4個字節)=的存儲器 59.605MB。

您將這些全部存儲在堆棧中,而不是使用指針並將其分配到堆上,這會導致堆棧溢出。

此外,在你的plugh和foo函數中,你正在返回一個全新的結構。爲什麼通過指針傳遞,修改對象,然後返回一個副本?每次調用這些函數時,都會分配另一個59.605MB的內存,因爲您正在返回一個副本。但是,由於您沒有使用該副本,因此編譯器可能會優化並刪除這些昂貴的副本。

+1

嗯,它甚至不止是因爲對齊,100MB的最佳部分! – 2011-04-18 19:59:16

1

它出現segfaults

0x8048471 <main>:  lea 0x4(%esp),%ecx 
0x8048475 <main+4>:  and $0xfffffff0,%esp 
0x8048478 <main+7>:  pushl -0x4(%ecx) 
0x804847b <main+10>: push %ebp 
0x804847c <main+11>: mov %esp,%ebp 
0x804847e <main+13>: push %esi 
0x804847f <main+14>: push %ebx 
0x8048480 <main+15>: push %ecx 
0x8048481 <main+16>: sub $0xb2d060c,%esp 
0x8048487 <main+22>: lea -0x7735958(%ebp),%eax 
0x804848d <main+28>: lea -0x3b9acb8(%ebp),%edx 
0x8048493 <main+34>: mov %edx,0x4(%esp)  <<---- segfaults here 
0x8048497 <main+38>: mov %eax,(%esp) 
0x804849a <main+41>: call 0x80483f4 <plugh> 

分配的6250萬個字節(32位int)堆棧幀後,在尋址新堆棧指針時,會出現故障。

大型結構應始終按引用傳遞。特別是考慮到foo()的邏輯。

+0

不只是通過引用傳遞,而是分配了堆。在main中查找堆棧分配的局部變量。 – 2011-04-18 20:07:32

0

你有沒有試過一個只傳遞給你的結構並不返回任何結果的函數? 沿線的東西void foo(level * var){//您的代碼在這裏修改var} 而在main中,您只需調用foo(& myVar)。

將如此巨大的結構作爲參數傳遞給函數或將其作爲返回值可能會給您帶來一些麻煩。另外,如果您確實需要返回值,請嘗試返回對您的結構的引用。 like level * foo(level * in){//你的代碼在這裏}。

而在主要你只是解引用函數的結果像級別myLvl = *(foo(& myOtherLvl))。這樣,你在你的函數中傳遞的所有東西都是你的結構,女巫基本上是整數。希望這可以幫助

相關問題