2016-07-04 240 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