質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

Vagrant

Vagrantは、VirtualBox上の仮想マシンを コマンドラインから作成してくれるソフトウェアです。 ビルド環境など容易に構築が可能です。

Q&A

解決済

4回答

1620閲覧

sizeof()のキャストについてのアンチパターン

imamoto_browser

総合スコア1161

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

GCC

GCCはGNU Compiler Collectionの略です。LinuxのC言語コンパイラのデファクトスタンダードであり、数多くの他言語やプラットフォームサポートもします。

Linux

Linuxは、Unixをベースにして開発されたオペレーティングシステムです。日本では「リナックス」と呼ばれています。 主にWebサーバやDNSサーバ、イントラネットなどのサーバ用OSとして利用されています。 上位500のスーパーコンピュータの90%以上はLinuxを使用しています。 携帯端末用のプラットフォームAndroidは、Linuxカーネル上に構築されています。

Ubuntu

Ubuntuは、Debian GNU/Linuxを基盤としたフリーのオペレーティングシステムです。

Vagrant

Vagrantは、VirtualBox上の仮想マシンを コマンドラインから作成してくれるソフトウェアです。 ビルド環境など容易に構築が可能です。

0グッド

0クリップ

投稿2018/01/20 06:26

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ページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答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
asm

総合スコア15147

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

imamoto_browser

2018/01/20 09:47

わかれば単純でした。結局割り当て方、間違ってるだけなんですね。
guest

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

yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

単純に「プログラムは意図した通りには動かない。書いた通りに動く」という格言通りなだけですね。

投稿2018/01/20 08:49

shsh_

総合スコア113

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

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
cateye

総合スコア6851

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yumetodo

2018/01/20 07:46

これはひどい、元記事に編集リクエスト投げてきました
cateye

2018/01/20 08:18

初心者+向けみたいなページなので、出来れば初心者にも理解しやすい形で提供してもらいたいです。
imamoto_browser

2018/01/20 08:24

>cateyaさん 回答ありがとうございます。構造体とポインタの名前は分けるべきというわけですね。 あとおっしゃることを言い換えると、mallocで構造体のメモリサイズを確保する際は、ポインタ型にキャストすべきではないということですね。 動いたり動かなかったりする理由は、50バイトで割り当てたつもりで他のリソースからfunc()にアクセスするコードを書いたことが原因でしょうか。
yumetodo

2018/01/20 09:10

>あとおっしゃることを言い換えると、mallocで構造体のメモリサイズを確保する際は、ポインタ型にキャストすべきではないということですね。 そんな話はしていないと思う
cateye

2018/01/20 09:22 編集

>構造体とポインタの名前は分けるべき は、可読性の問題なのでそうしなくてはいけないわけではありません。 >mallocで構造体のメモリサイズを確保する際は、ポインタ型にキャストすべきではない 違います! malloc()が返すのはvoid*ですから構造体へのポインタへのキャストは必要です(aaa = (struct aaa*)malloc(sizeof(struct aaa)); )。が、確保するメモリは構造体のサイズsizeof(struct aaa)です。 >動いたり動かなかったりする理由 malloc()が確保するのは一定量(4KBとか環境次第。ここから先はユーザか確保したサイズと言う意味ではなく実際にコンパイラがOSから取ってきて、割り当てた領域サイズの事です)です。それをmalloc()が呼ばれる度に切り崩して使います。(足りなくなれば、また確保する)なので、動く場合は確保した領域内にアクセスした場合で、動かないのは確保した領域をはみ出した場合です。こればかりはコンパイラの作りとOSで確保できるメモリサイズによります。
imamoto_browser

2018/01/20 09:46

読み違えてました。malloc()の返り値はvoid*なので構造体へのポインタへのキャストが必要で、aaa = (struct aaa *) malloc(sizeof(struct aaa *));だとsizeof()の引数が構造体へのポインタのサイズで場合によってははみ出してしまうよってことでまずいってことですね。
cateye

2018/01/20 10:44

yumetodoさんの回答にもありますが、ポインタ領域を確保してはダメと言うわけではありません。要は、何の領域を確保するのか?(構造体なのか構造体へのポインタなのか)・・・と言うことです。あと、C99以降は(struct aaa *)のポインタのキャストは不要ですね。(C++の影響でしょうか・・・反省)
yumetodo

2018/01/20 12:16

>C++の影響でしょうか むしろC++はその暗黙変換がないのでCより厳格かと
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問