• ベストアンサー

メモリ確保の謎。

C言語のメモリの確保の所でふと疑問に思ったのですが、 malloc,calloc,realloc,memset,memcpyなどの関数を使うときって #include <stdio.h> #include <stdlib.h> #include <memory.h> #include <malloc.h> とか書かないといけないと本にはありますが、#include <stdio.h>だけで なんのエラーにもならずに実行できてしまうのはなぜでしょうか? 実際のプログラムにはmallocとreallocしか使ってないのですが、#include <stdio.h>でできてしまいます。 でも教科書には他にも書かなきゃいけないとかいてありますが、なぜ書かなくても実行できてしまうのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • shige_70
  • ベストアンサー率17% (168/946)
回答No.1

それはたまたま動いただけです。 別の環境ではコンパイルに失敗する場合もあると思います。 ヘッダファイルには、そういったライブラリ関数の引数や返り値に関する情報(プロトタイプ宣言といいます)が納められていて、それをインクルードすることで、『正しく』コンパイルできるのです。 ヘッダをインクルードしていれば、ミスで引数を間違えた時にもちゃんとコンパイルエラーになってくれるのでわかります。しかし、インクルードしてないと、逆に正しいはずの時にエラーになったり、もしくは正当性を確認せずよろしくコンパイルしてくれたりします。 ですから、必ず書いておくべきです。たまたま書かなくてもコンパイルに成功して正しく動いたとしてもあくまでそれは偶然でしかないのです。 このことは、メモリ系の関数に限らずすべてにおいてそうですので、心に留めておいてください。どの関数がどのヘッダを必要とするかは関数のマニュアルを参照してください。 ちなみに、一般的には、malloc(),realloc()しか使わないのであれば(calloc()も)、通常はstdlib.hだけでこと足りるはずです。memset(),memcpy()もstring.hだけあれば使えます。

usui323
質問者

お礼

回答ありがとうございました。 次からはきちんと書くようにしようと思います。

その他の回答 (2)

  • shige_70
  • ベストアンサー率17% (168/946)
回答No.3

#1です。 #2の方の回答のように認識していても問題はないのですが一部勘違いされている部分があるようなので失礼ながら指摘させて戴きます。 関数のプロトタイブ宣言を怠ると、帰り値はたしかにintがたと見なされますが、引数は通常、プログラム中で使用されている箇所で記述した引数がそのまま渡ります(書かれているとおりにスタックに積まれる)。そして、関数側ではその関数の仕様どおりに引数を取り出します。(スタックから引き出される)。 したがって、実際は、ヘッダのインクルードを忘れても、引数に関しては問題は発生しません。 プロトタイプ宣言があれば、コンパイラが引数の仕様を 知ることができ、もし間違った引数を与えようとすると警告を出します。こうすれば、プログラム作成者がミスに気づくことができます。プロトタイプ宣言を省略すれば、コンパイラは関数にどういう引数を与えるのが正しいかを知るよしもありませんから、プログラム中で使用されている引数が正しいとみなしてコンパイルするしかないのです。 プロトタイプ宣言というのは、(ANSI以降の)新しい仕様で、(ANSIより前のいわゆるK&R時代の)昔のC言語では存在しませんでした。そのころは関数呼び出しで正しい引数を書くことは自己責任であり、コンパイラではミスを検出しなかったのです。まあ、そのころもヘッダファイルというのはあってちゃんとインクルードしてあげないといけないのは同じだったんですけどね。

usui323
質問者

お礼

回答ありがとうございました。 詳しい回答ありがとうございます。

  • V-bravo-U
  • ベストアンサー率51% (155/301)
回答No.2

 ヘッダーファイルの中には関数宣言も含まれています。関数宣言を 怠ると「全てint型の引数を持つint型を返す関数」としてコンパイル されてしまうこともあります。質問者のコンパイラはこの仕様でコンパイル されているものと推測されます。  今回の場合ですとmalloc関数とrealloc関数しか使われていないということ ですが、まさにたまたま正常に動いているケースです。なぜなら、一般的に int,unsigned int,ポインタ,これらのビット幅は同じで幸いにも mallocもreallocも戻り値と引数が全てint型に一致するからです。 memsetとmemcpyも同様の理由です。  #includeを端折ってコンパイルが通っても実行結果が意図したものに ならない場合もあります。例えば数学関数を使いたいのに#include <math.h>を 省略したために返ってくる結果が0.0か1.0のどちらかしか返ってこないという こともあります。このため、デバッグを困難になる原因になります。  ですから、関数(自作/他作/標準問わず)を使うときは使いたい関数の ヘッダーファイルを必ずincludeする必要があります。絶対に忘れないように しましょう。

usui323
質問者

お礼

回答ありがとうございました。 次からは忘れないようにしようと思います。

関連するQ&A