[英]Modify pointer of pointer of struct
我創建一個結構,將指針的指針傳遞到函數中,然后調用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的定義:
typedef struct TFeld
{
bool Schiff_Vorhanden = false;
bool Ueberprueft = false;
bool Schiff_Versunken = false;
} TFeld;
我注釋掉的部分只是在使用測試功能時崩潰了程序。
有人可以向我解釋這種行為。
有什么問題 ?
在InitField()
,參數Feld
被聲明為指向TFeld的指針。
*Feld
因此是TFeld
的指針。 它已正確初始化為正確大小的新分配內存區域。
然后,您調用test()
並傳遞*Feld
作為參數。 不幸的是,您也調用了Feld
參數,因此這些變量的類型不同並且可能引起一些麻煩。 但這不是問題。 測試功能應該可以實現您的期望。
當您返回InitField()
,然后嘗試訪問已初始化的元素:
Feld[i]->Schiff_Versunken = ... //ouch !!!
這會將指針指向指針,並訪問該表中的第ith個指針。 但是由於指針的指針只是一個Poitner而不是數組,因此您將獲得一個完全損壞的指針。 然后,使用->
假裝它指向TFeld
來取消引用該惡意指針。 然后,當您向該惡意地址分配一個值時,您的行為就不確定(可能是段錯誤,可能凍結,可能是任何事情)。
編輯:有關指針解引用的其他信息:
運算符*
->
和[]
具有必須習慣的優先順序 。 讓我們看一下TFeld **Feld
:
*Feld[i]
與*(Feld[i])
相同,因為首先應用[]
,然后僅應用*
。 順便說一句,進一步講,應用指針算術規則,它與*(*(Feld+i))
。 無論如何,這不是你想要的 *Feld[i].xxx
與*((Feld[i]).xxx)
因為.
具有比*
高的優先級。 因為Feld[i]
不是TFeld
類型, TFeld
不會編譯 Feld[i]->xxx
與(Feld[i])->xxx
(因為[]
和->
具有相同的優先級,但是當兩者出現時,它們都是從左到右應用的)。 這進一步與(*(Feld[i])).xxx
。 仍然不是您想要的。 但是讓我們可視化以了解以不同順序應用取消引用的影響。 最重要的是您需要的。 根本是應避免的事情:
怎么解決 ?
我建議將注釋掉的部分更改為:
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;
}
或者,如果您不喜歡星星和黏附:
Feld[0][i].Schiff_Versunken = false;
Feld[0][i].Schiff_Versunken = false;
Feld[0][i].Ueberprueft = false;
雙重定向總是有些棘手。 如有疑問,請添加一些括號。
最后一句話:我在這里假設InitField()
是使用指向TFeld
的有效指針來TFeld
,因此*Feld
無疑會指向TFeld
的指針。 如果是這種情況,則您的內存分配指針可能會寫入內存中的任何位置,從而再次導致內存損壞。 如有疑問,請對您的問題進行編輯,以顯示調用代碼,以便我檢查。
Feld
是指向結構數組的指針。 因此,您必須(1)取消引用指針,然后(2)索引數組,最后(3)訪問struct內部的字段。
有兩種方法可以在for
循環中編寫此代碼: 您更喜歡哪一個是口味問題:
(*Feld)[i].Schiff_Versunken = false; // option 1
(*Feld + i)->Schiff_Versunken = false; // option 2
在函數內部直接進行操作時會有所不同。 因為這里Feld
是指向test()
結構的指針,而它是指向initField()
結構的指針。
當您使用malloc()時,指向該結構的指針已初始化,因此在test()
內部訪問時不會崩潰。 但是指向該指針的指針仍未初始化,因此在initField()
引起了seg錯誤。
因此,您必須正確分配雙指針。 檢查此鏈接以供參考: C-使用雙指針的動態內存分配
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.