2016-07-04 7 views
2

구조체를 생성하고 함수 포인터에 포인터를 전달한 다음 malloc()을 호출하십시오. 그건 모두 잘 작동합니다. 그러나 메모리에 액세스하려고하면 프로그램이 정지됩니다. 다른 함수를 호출하고 메모리에 액세스를 변경하면 모든 것이 잘 작동합니다. TFeld의 definiton와구조체의 포인터 포인터를 수정하십시오.

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; 
    } */ 
} 

은 : 테스트 기능이 작동 사용하는 동안 내가 주석

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 pointer ?! : D –

답변

4

무엇이 문제인가?

InitField()에서 매개 변수 Feld은 TFeld에 대한 포인터의 포인터로 선언됩니다. 따라서 에 대한 포인터입니다. 올바른 크기의 새로 할당 된 메모리 영역으로 올바르게 초기화됩니다.

그런 다음 test()을 인수로 전달합니다 (*Feld). 불행하게도 변수 Feld을 호출하여 변수의 유형이 다르고 두통을 일으킬 수 있습니다. 그러나 이것은 문제가 아닙니다. 테스트 기능은 예상대로 작동해야합니다.

당신이 다음 초기화 한 요소에 액세스하려고 다시 InitField()에있어

는 :

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

이 포인터와 해당 테이블에 i 번째 포인터를 액세스 포인터를합니다. 하지만 포인터 포인터가 포인터가 아니고 배열이 아니므로 완전히 손상된 포인터가 다시 나타납니다. 그런 다음이 불량 포인터를 ->으로 역 참조하여 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; 

더블 indirections가에 allways 조금 까다로운됩니다. 의심이들 때마다 괄호를 추가하십시오.

마지막 단어 : 나는, InitField()TFeld에 대한 포인터에 대한 유효한 포인터라는 것을 여기에 가정 있도록 *FeldTFeld에 대한 포인터에 대한 의심의 여지 점없이. 이 경우 메모리 할당 포인터가 메모리 어디에나 쓸 수있어 메모리 손상을 다시 일으킬 수 있습니다. 의심 스럽다면, 내가 확인할 수 있도록 호출 코드를 보여주는 질문을 편집하십시오.

+0

좋아, 그렇게 부르는 것 같아. (* Feld [i]). Schiff_Versunken = false; * Feld [i] -> Schiff_Versunken = false; 권리? 왜냐하면 그것은 내가 처음에는 이해하지 못했기 때문입니다. (* Feld) [i] .Schiff_Versunken = false; (* Feld [i]와는 다릅니다.) Schiff_Versunken = false; – nuclear

+0

@ 핵 귀하의 혼란을 이해합니다. 우선 순위에 관한 편집을 참조하십시오.나는 또한 다른 의미를 나타내는 스키마를 추가했다. (* Feld) [i]와'* Feld [i]' – Christophe

1

Feld은 구조체의 배열에 대한 포인터입니다. 따라서 (1) 포인터를 역 참조하고, (2) 배열에 인덱스를 지정하고, 마지막으로 (3) 구조체 내부의 필드에 액세스해야합니다.

for 루프 내에 다음과 같은 두 가지 방법으로 작성할 수 있습니다. 당신이 더 좋아하는 사람은 취향에 관한 질문입니다.

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

함수 내에서 직접 할 때 차이가 있습니다. 여기 Feld은 에있는 구조체에 대한 포인터이기 때문에 구조체에 대한 포인터는 initField()에있는 포인터입니다.

malloc()을 사용할 때 구조체에 대한 포인터가 초기화되어 있으므로 test() 안에 액세스 할 때 충돌이 발생하지 않았습니다. 그러나 포인터에 대한 포인터가 아직 초기화되지 않았으므로 initField()에 seg 오류가 발생합니다.

따라서 이중 포인터를 올바르게 할당해야합니다. C - dynamic memory allocation using double pointer

관련 문제