1

1時間ほど探し回りました。ここに質問を投稿したほうがいいと思います。

コードを簡素化します。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;
}
4

3 に答える 3

5

新しく割り当てられたメモリへのポインターを保持していないため、代わりに初期化されていないポインターを使用し、未定義の動作を取得します。

a変数を に渡しますallocMyStruct()が、その呼び出しは (他のすべてと同様に) value によって行われるため、関数内で変数に割り当てられた新しい値はinの値に影響しませamain()

新しいポインター値を返すallocMyStruct()か、ポインターへのポインターを取るように変更します。私は前者を好みます。よりクリーンで、関数の戻り値を使用すると、多くの場合、より良いコードが得られます。

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

上記のコードは、メモリの割り当ても合理化し、malloc()実際に必要な 3 つの部分に「スライス」される 1 つの大きな呼び出しですべてを実行します。

ちなみに、のサイズarr1が常に 10 の場合、動的に割り当てても意味がありませんint arr1[10];。構造体宣言にあるだけです。

于 2013-11-04T10:28:59.943 に答える
2

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);
}
于 2013-11-04T10:30:33.700 に答える
1

を呼び出すとvoid allocMyStruct (myStruct * a, int num)aポインターは値として渡され、aパラメーターは からのポインターのローカル コピーになります。3 つの関数のいずれかで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 は、同じアドレスの複数の解放について正しいです。Linux では、2 回解放すると即座にクラッシュします。そして、彼はより簡単な解決策を持っています。

于 2013-11-04T10:30:56.690 に答える