2016-07-04 248 views
2

我創建了一個結構體,將指針指針傳入函數,然後調用malloc()。這一切都很好。 但是,如果我嘗試訪問內存,該程序只會凍結。如果我調用另一個函數並更改訪問內存,那麼一切正常。修改結構體指針的指針

void test(TFeld *Feld, TEinstellung E) 
{ 
int i; 

    for (i=0;i<E.Groesse_X*E.Groesse_Y;i++) 
    { 
     Feld[i].Schiff_Vorhanden = false; 
     Feld[i].Schiff_Versunken = false; 
     Feld[i].Ueberprueft = false; 
    } 
} 

void initField (TEinstellung E, TFeld **Feld) 
{ 
    int i; 

    *Feld = (TFeld*)malloc(E.Groesse_X*E.Groesse_Y*sizeof(TFeld)); 

    test(*Feld,E); 

    /* for (i=0;i<E.Groesse_X*E.Groesse_Y;i++) 
    { 
     Feld[i]->Schiff_Versunken = (bool*)false; 
    // (*Feld[i]).Schiff_Versunken = false; 
     //Feld[i]->Ueberprueft = false; 
    } */ 
} 

與TFeld的definiton:

typedef struct TFeld 
{ 
    bool Schiff_Vorhanden = false; 
    bool Ueberprueft = false; 
    bool Schiff_Versunken = false; 
} TFeld; 

我註釋掉的部分,而使用測試功能工作剛剛墜毀的程序。

有人可以請解釋我的行爲。

+3

你在哪裏寫過'Feld [i] - >'你可能意思是'(* Feld)[i]。' – immibis

+0

在你的'struct' typedef中,你可以省去'TFeld你第一次擁有它。如在'typedef struct {...} TFeld;' –

+0

bool指針?! :D –

回答

4

最新問題?

InitField()中,參數Feld被聲明爲指向TFeld的指針。

*Feld因此是指向TFeld的指針。它被正確初始化爲正確大小的新分配的內存區域。

然後您打電話test()通過*Feld作爲參數。不幸的是,您也可以調用參數Feld,以便這些變量的類型不同並且可能會導致一些頭痛。但這不是問題。測試功能應該做你期望的。

當你回到InitField()然後嘗試訪問您已初始化的元素:

Feld[i]->Schiff_Versunken = ... //ouch !!! 

這需要指針,指針和該表中訪問的第i個指針。但是當你的指針指針只是一個poitner而不是一個數組時,你會得到一個完全損壞的指針。然後,您假裝它指向TFeld,將這個流氓指針解除引用->。當你給這個流氓地址賦值時,你有未定義的行爲(可能是段錯誤,可能會凍結,可能是任何東西)。

編輯:關於指針的更多信息提領:

運營商*->[]有,你有一個order of precendence習慣。讓我們來看看TFeld **Feld

  • *Feld[i]是相同的是*(Feld[i])因爲第一[]應用,然後只*。順便說一下,進一步,並應用指針算術規則,它與*(*(Feld+i))相同。無論如何,這不是你想要的
  • *Feld[i].xxx*((Feld[i]).xxx)相同,因爲.*具有更高的優先級。這不會編譯,因爲Feld[i]的類型是不TFeld
  • Feld[i]->xxx相同(Feld[i])->xxx(因爲[]->具有相同的優先級,但是當兩者都顯示他們是從左側應用到右側)。這與(*(Feld[i])).xxx進一步相同。而且還不是你想要的。

但讓我們通過可視化了解以不同順序應用解引用的影響。最重要的是你需要的。該botom是你應該避免什麼:

enter image description here

如何解決?

我建議改變註釋掉部分爲:

for (i=0;i<E.Groesse_X*E.Groesse_Y;i++) 
{ 
    (*Feld)[i].Schiff_Versunken = false; 
    (*Feld)[i].Schiff_Versunken = false; 
    (*Feld)[i].Ueberprueft = false; 
} 

或者,如果你不喜歡的明星和partenheses:

Feld[0][i].Schiff_Versunken = false; 
    Feld[0][i].Schiff_Versunken = false; 
    Feld[0][i].Ueberprueft = false; 

雙間接性是永諾有點棘手。每當你有疑問時,加一些括號。

的最後一句話:我這裏假設InitField()被稱爲一個有效的指針的指針TFeld,使*Feld將毫無疑問點的指針TFeld。如果情況如此,內存分配的指針可能會寫入內存中的任何位置,從而導致內存損壞。如果有疑問,請對您的問題進行編輯以顯示調用代碼,以便我可以檢查。

+0

好的,所以我想這就像是(* Feld [i])。Schiff_Versunken = false;等於* Feld [i] - > Schiff_Versunken = false;對?因爲那是我第一次不明白的(*費爾德)[i] .Schiff_Versunken = false;不同於(* Feld [i])。Schiff_Versunken = false; – nuclear

+0

@核我明白你的困惑。請參閱我的關於優先順序的編輯。我還添加了一個模式來顯示不同的含義'(* Feld)[i]'和'* Feld [i]' – Christophe

1

Feld是一個指向結構數組的指針。所以你必須(1)解引用指針,然後(2)索引到數組中,最後(3)訪問struct中的字段。

在您的for循環中有兩種編寫方法;哪一個你更喜歡的是一個品味的問題:

(*Feld)[i].Schiff_Versunken = false; // option 1 
(*Feld + i)->Schiff_Versunken = false; // option 2 
0

當你在一個函數內部直接進行操作時,會有區別。因爲這裏的Feld是指向test()中的結構的指針,而它是指向指向initField()中的結構的指針。

當你使用malloc()時,指向結構的指針被初始化了,因此它在test()內部訪問時並沒有崩潰。但指針指針仍未初始化,因此導致initField()中的seg故障。

所以你必須正確地分配雙指針。檢查這個鏈接以供參考:C - dynamic memory allocation using double pointer