- ベストアンサー
構造体配列のメモリ確保
以下のようなプログラムを作りました。 make_mem関数のなかで構造体のメモリを確保し、 データを代入しています。 しかし、mainに返ってくると値が代入されていません。 よく調べてみると、mainで宣言してあるdataのアドレスが 変更されていません。 どのようにすれば、meake_memoのなかでメモリ確保し、 データを代入できるのでしょうか? 教えてください。 実際の使用しているプログラムはmake_memoのなかで DBを開き、そのデータを配列に代入しているので、 main関数の中では配列の大きさがわかりません。 #include <stdio.h> typedef struct { int a; int b; }DATA; int make_mem(DATA *data){ int i; data=(DATA *)calloc(10,sizeof(DATA)); printf("calloc %p\n",data); for (i=0;i<10;i++){ data[i].a = i; printf("data[%d].a = %d\n",i,data[i].a); } return 0; } int main(int argc,char *argv[]){ DATA *data; int i; printf("before %p\n",data); make_mem(data); printf("after %p\n",data); for (i=0;i<10;i++){ printf("data[%d].a = %d\n",i,data[i].a); } return 0; }
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
> freeで開放していないからってことですか? > この場合はmainのなかでfreeをつかうってことですかね? この場合は、そうなるとおもいます。 メインの最初でdataをNULLなどで初期化しておいて メインを終了する前にdataがNULLでなければ freeするという感じではないでしょうか。
その他の回答 (3)
- yasuch
- ベストアンサー率41% (27/65)
みなさんがヒントを出されて、 理解されたようですのでそろそろ正解を。 ただし、このまま動かすとメモリリークしますよ。 #include <stdio.h> typedef struct{ int a; int b; }DATA; int make_mem(DATA **data){ int i; *data=(DATA *)calloc(10,sizeof(DATA)); printf("calloc %p\n",*data); for (i=0;i<10;i++){ (*data)[i].a = i; printf("data[%d].a = %d\n",i,(*data)[i].a); } return 0; } int main(int argc,char *argv[]){ DATA *data; int i; printf("before %p\n",data); make_mem(&data); printf("after %p\n",data); for (i=0;i<10;i++){ printf("data[%d].a = %d\n",i,data[i].a); } return 0; }
お礼
回答ありがとうございました。 (*data)[i].a = i; ↑の書き方がわからず、悩んでいました。 >ただし、このまま動かすとメモリリークしますよ。 freeで開放していないからってことですか? この場合はmainのなかでfreeをつかうってことですかね?
- hitomura
- ベストアンサー率48% (325/664)
まずは簡単なクイズです。次の結果は? #include <stdio.h> void f(int a) { a=1; } int main(int argc,char** argv) { int a=0; f(a); printf("%d\n",a); return 0; } 答は「0が表示される」です。Cの関数はパラメータが値渡しされるため、パラメータを変更しても元の変数に影響しません。 この辺は理解されてますよね? では本題。上のaの定義のintをDATA*に変えると? …そう、パラメータとして受け取った値(この場合DATA *data)は値渡しされているため、関数内で変更しても元の変数に影響を与えません。つまり、ポインタ自体の値が元の関数に渡っていないのです。 解決法は、「ポインタを渡す」です。もうポインタで渡しているよと言われるかもしれませんが、そのポインタのポインタを渡すように変更するのです。つまり、 int make_mem(DATA **data) に変えるわけです。当然、make_memの内容もそれにあわせて書き換える必要があります。
お礼
>この辺は理解されてますよね? はい。理解しているつもりです make_memo(DATA *data)になっているのでアドレス渡しに なっていると思っていました。 >当然、make_memの内容もそれにあわせて書き換える必要があります。 このへんが、よくわからないのですが 調べてみます。 ありがとうございました。
- phoenix343
- ベストアンサー率15% (296/1946)
DATA *dataを、int dataに置き換えると分かると思います。関数内部でdataの値を変えても、外に出たときは変わっていませんよね。値渡しといって関数内部で変更しても反映されません。反映させるにはint *dataにしてアドレス渡しにしなければならないのです。 これと同じ要領で、DATA **dataとすればよいです。 …と簡単な説明ですが、参考になれば。
お礼
make_memo(DATA *data)になっているのでアドレス渡しに なっていると思っていました。 ダブルポインタにするってことですね。 ありがとうございました。
お礼
わかりました。 ありがとうございました。 回答してくださった方まとめてのお礼で 申し訳ありませんが、ダブルポインタを 使用する事は目からウロコでした。 ありがとうございました。