2013-11-04 4 views
0

약 1 시간 동안 검색되었습니다. 나는 여기서 질문을 게시하는 것이 더 나을 것이라고 생각한다.구조체를 초기화 할 때 왜 segfault가 발생합니까?

코드를 단순화합니다. segfault는 initMyStruct 함수에 있습니다.

#include "stdlib.h" 

typedef struct { 
     int * arr1; 
     int * arr2; 
} myStruct; 

void allocMyStruct (myStruct * a, int num) { 
     a = malloc(sizeof(myStruct)); 
     a->arr1 = malloc(10*sizeof(int)); 
     a->arr2 = malloc(10*num*sizeof(int)); 
} 
void initMyStruct (myStruct * a, int num) { 
     int i; 
     for (i = 0; i < 10; i++)  a->arr1[i] = 0; 
     for (i = 0; i < 10*num; i++) a->arr2[i] = -1; 
} 
void freeMyStruct (myStruct * a, int num) { 
     int i; 
     for (i = 0; i < 10; i++)  free(a->arr1); 
     for (i = 0; i < 10*num; i++) free(a->arr2); 
     free(a); 
} 
int main (void) { 
     int num = 3; 
     myStruct * a; 
     allocMyStruct (a, num); 
     initMyStruct (a, num); 
     freeMyStruct (a, num); 
     return 1; 
} 
+1

과 관련이 없지만 'main' 함수가 1을 반환하는 이유는 무엇입니까? 프로그램이 1을 반환하면 AFAIK라는 오류가 발생했음을 나타냅니다. std lib에는 매크로가 정의되어 있습니다 :'#define EXIT_SUCCESS 0'과'#define EXIT_FAILURE 1' ... –

답변

4

새로 할당 된 메모리에 포인터를 보관하지 않으므로 대신 초기화되지 않은 포인터를 사용하고 정의되지 않은 동작이 발생합니다.

당신은 allocMyStruct()a 변수를 전달하지만 통화 가치에 의해 (모든 다른 이들처럼), 그래서 함수가 main()에서 a의 값에 영향을 미치지 않는 내부의 새 값이 할당된다.

allocMyStruct()이 새 포인터 값을 반환하거나 포인터를 포인터로 사용하도록 변경하십시오. 에 "슬라이스"다음 하나의 큰 malloc() 호출에 모든 일을

myStruct * allocMyStruct(int num) 
{ 
    myStruct *p; 

    if((p = malloc(sizeof *p + 
       10 * sizeof *p->arr1 + 
       10 * num * sizeof *p->arr2)) != NULL) 
    { 
    p->arr1 = (int *) (p + 1); 
    p->arr2 = p->arr1 + 10; 
    } 
    return p; 
} 

위의 코드는, 메모리 할당을 간소화 : 나는 그것이 더 깨끗하고 함수의 반환 값을 사용하는 것이 종종 더 나은 코드로 연결, 전자를 선호 당신이 실제로 필요로하는 세 부분.

arr1의 크기가 항상 10 인 경우 동적 할당이 필요하지 않으므로 struct 선언에 int arr1[10];이어야합니다.

+1

+1 최적화 된'malloc' 호출을 위해서 +1 저는 C 프로그래밍 언어 _를 여전히 기다리고 있습니다. 그래서 제 질문을 용서합니다. :''p + 1''은 언제나 정확할 것인가, 아니면'p + sizeof * void' 또는 뭔가 여야 하는가? –

+1

'(int *) (p + 1)'이'p-> arr1'을 위해 어떻게 정렬되어 있는지 어떻게 알 수 있습니까? –

+1

@AlterMann :이 경우 구조체는'int *'만 포함하기 때문에 여기서 구조체 정렬이 필요하지 않을 것입니다. 그러나 아마'p-> arr1'이'p + 1'에 있다고 가정하는 위험성을 언급 할 가치가 있습니다. 구조체가 성장하고 새로운 유형이 추가 될 때, 문제가 될 수 있다고 생각합니다. 각 멤버의 비트 수는 명시 적으로 지정됩니다 ... 아니면 단지 편집증에 빠졌습니까? –

1

a가 초기화되지 않은 사용, 변화 : 또한

myStruct * allocMyStruct (int num) { 
     myStruct *a; 

     a = malloc(sizeof(myStruct)); 
     a->arr1 = malloc(10*sizeof(int)); 
     a->arr2 = malloc(10*num*sizeof(int)); 
     return a; 
} 
myStruct * a = allocMyStruct(num); 

,

void freeMyStruct (myStruct * a, int num) { 
     int i; 
     for (i = 0; i < 10; i++)  free(a->arr1); 
     for (i = 0; i < 10*num; i++) free(a->arr2); 
     free(a); 
} 

당신이 전화

void freeMyStruct (myStruct * a) { 
     free(a->arr1); 
     free(a->arr2); 
     free(a); 
} 
1

이어야합니다 무료 기능 루프에 대한 필요가 없습니다 void allocMyStruct (myStruct * a, int num)a 포인터가 값으로 전달되고 a 매개 변수는 main에있는 포인터의 로컬 복사본이며 세 가지 기능 중 하나에서 로컬 a을 변경하면 main으로 변경되지 않습니다.

이 경우 이중 포인터를 함수 인수로 사용해야하므로 해당 함수는 포인터의 주소를 가져 와서 수정할 수 있습니다.

#include "stdlib.h" 

typedef struct { 
     int * arr1; 
     int * arr2; 
} myStruct; 

void allocMyStruct (myStruct ** a, int num) { 
     *a = malloc(sizeof(myStruct)); 
     (*a)->arr1 = malloc(10*sizeof(int)); 
     (*a)->arr2 = malloc(10*num*sizeof(int)); 
} 
void initMyStruct (myStruct ** a, int num) { 
     int i; 
     for (i = 0; i < 10; i++)  (*a)->arr1[i] = 0; 
     for (i = 0; i < 10*num; i++) (*a)->arr2[i] = -1; 
} 
void freeMyStruct (myStruct ** a, int num) { 
     free((*a)->arr1); 
     free((*a)->arr2); 
     free(*a); 
     *a = NULL; 
} 
int main (void) { 
     int num = 3; 
     myStruct * a; 
     allocMyStruct (&a, num); 
     initMyStruct (&a, num); 
     freeMyStruct (&a, num); 
     return 1; 
} 

편집 : Alter Mann은 동일한 주소를 여러 번 해제하는 것이 좋습니다. 리눅스에서는 두 번 해제하면 즉시 충돌이 발생합니다. 그리고 그는 더 간단한 해결책을 가지고 있습니다.

관련 문제