qiitaの記事を読んでC言語のプログラミングでのアンチパターンを学習しているのですが、
c
1void func() { 2 int loop = 0; 3 struct aaa *aaa = NULL; 4 aaa = (struct aaa *) malloc(sizeof(struct aaa *)); 5 if( NULL == aaa ) { 6 return RET_NG; 7 } 8 // 何か処理 9 free(aaa); 10 return RET_OK; 11}
サイトの解説によると、malloc時に指定したサイズに構造体の型ではなくポインタ型を指定すると、intサイズ分しかメモリを確保できないので
意図した動作にならないとあります。
なぜ、
aaa = malloc(sizeof(struct aaa)); // もしくはsizeof(*aaa)
とするのがベターなのでしょうか。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答4件
0
ベストアンサー
ベターとかじゃなくて単純にバグです
printf("sizeof(struct aaa*)=%d\n", sizeof(struct aaa*)); printf("sizeof(struct aaa) =%d\n", sizeof(struct aaa));
を比べてください
int分というかポインタサイズしか取得できません。
投稿2018/01/20 06:48
編集2018/01/20 06:49総合スコア15147
0
ちょっと元記事にも編集リクエスト投げましたが、こっちにも。
構造体を動的に確保する場合、普通はmalloc
/calloc
関数を利用すると思います。
ここで仮に構造体Hogeがあったとして
c
1typedef struct { 2 int value; 3} Hoge;
要素数1だけ動的確保する場合
c
1// 構造体の大きさ * 要素数 2Hoge* hoge_p = malloc(sizeof(Hoge) * 1);
のようにします(C89/C++ではできませんが、C99以降のCではvoid*
型の値は他のポインタ型へ暗黙変換されるので、malloc
の戻り値をキャストする必要はありません。)
ここでこのコードは次のコードと等価です。
c
1Hoge* hoge_p = malloc(sizeof(Hoge));
でここまで書くと、「ふっふ~ん、わかった、malloc
に渡すsizeof
にはポインタじゃない型を書けばいいんでしょ?」という誤解をするかもしれません。そこで次のコードを見てください。
c
1#include <stdio.h> 2#include <stdlib.h> 3typedef struct { 4 int value; 5} Hoge; 6 7int main(void) 8{ 9 const size_t col_size = 4; 10 const size_t row_size = 3; 11 Hoge** hoge_determinant = malloc(sizeof(Hoge*) * row_size); 12 13 // init 14 Hoge* tmp = calloc(sizeof(Hoge), col_size * row_size); 15 for(size_t i = 0; i < row_size; ++i) hoge_determinant[i] = &tmp[i * row_size]; 16 17 //print 18 for(size_t i = 0; i < row_size; ++i){ 19 putchar('|'); 20 for(size_t j = 0; j < col_size; ++j){ 21 if(j) putchar(' '); 22 printf("%d", hoge_determinant[i][j].value); 23 } 24 puts("|"); 25 } 26 27 return 0; 28}
https://wandbox.org/permlink/esJmmwvPmD99qpbF
malloc(sizeof(Hoge*) * row_size)
とあります。あれ、ちがうの?
ここでsizeof(Hoge*)
としたのは、要素数row_size
だけHoge*
型の動的確保するためです。
すなわち、渡すべきは要素型の型の大きさです。
投稿2018/01/20 10:28
総合スコア5850
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
まず、ポインタのサイズと構造体のサイズが違うことは分かりますか?
構造体とポインタの名前が同じというのも誤解を招きますね。struct AAA *aaa= NULL;の方がまだ分かりやすいかな?
で、たとえば構図体のサイズが50バイトあった場合に、そのポインタは4バイト(32ビット環境の場合)になります。ようは、sizeof(AAA)とsizeof(aaa)は、各々50と4になる訳です。なので、4バイトの領域をはみ出して何か操作を行えば、確保した領域外にアクセスすることになります。場合によっては何も起こらないかもしれませんが、通常はメモリを破壊することになりますd^^・・・したがって、動いたり動かなかったり・・・厄介なバグになります。
#記事の記述にも問題があります。”ポインタ型を指定した場合、intサイズ分しかメモリを確保できません”はポインタとintが同じ環境でしか意味を持ちません。正しくは、”ポインタのサイズ分”と言うべきだと思います。
投稿2018/01/20 07:10
編集2018/01/20 07:13総合スコア6851
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/01/20 08:18
2018/01/20 08:24
2018/01/20 09:10
2018/01/20 09:22 編集
2018/01/20 09:46
2018/01/20 10:44
2018/01/20 12:16
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/01/20 09:47