ID非公開

2020/9/17 16:03

44回答

【C言語】data[size]で宣言するとfreadがおかしくなるのは何故か?

【C言語】data[size]で宣言するとfreadがおかしくなるのは何故か? C言語初心者です。 short型の数字がN個記録されたファイル(2*Nbytes)を読み出し、配列に格納しようと考えています。 そこで、以下のようなプログラムを書きました。 int size = N; short data[N]; //問題点? int num = fread((char *)data, sizeof(short), sizeof*N, fp); printf("num=%d",num); for(int i = 0;i < N;i++){ printf("data[%d]=%d\n",i,data[i]); } ※ ・fp等はバイナリモードで正常にデータファイルが開かれているとします。 ・適切なライブラリがincludeされているとします。 ・Nは巨大であるとします。(RAMで読み取れる程度に大きい) ※ この問題が発生した実際の環境は N=2048000 sizeof(short)=2 RAM=1GBでした。 試しに実行してみると、2回に1回程度、 num=0 data[0]=0 data[1]=0 … … … のようになってしまいます。 (freadの返り値が0になる) short data[N]; が怪しいと思ったので short *data = (short *)malloc(sizeof(short)*N); のように、mallocでメモリを確保してからfreadするようにしてみました。 すると、fread()は100%(500回ぐらい試して)正常にデータを読んでくれるようになりました。 ここで質問です。 なぜ、 short data[N]; の時はfread()は読み込んでくれず、 malloc() の時はfread()で全て読み取ってくれたのでしょうか? short data[N]; のNが大きすぎる場合、メモリーが確保される前に次の行に処理が進んでしまうのでしょうか? それともmalloc()で確保した場合も、確保される前に次の行へ行ってしまうので、fread()が0になる可能性があるのでしょうか? (今回mallocで100%上手く行ったのは単なる偶然だったということでしょうか?) まだ初心者で配列とmallocのメモリ確保の違いや、偶然うまくいったことを覚えていて、勘違いしているだけかもしれませんが、よろしくお願いします。

C言語関連27閲覧

ベストアンサー

0

> この問題が発生した実際の環境は > N=2048000 > sizeof(short)=2 > RAM=1GBでした。 > short data[N]; //問題点? 関数内で定義している場合は問題ですね。 Windows 上であればスレッドのデフォルトのスタックサイズは 1MB です。 これには、関数呼び出し時の引数や関数内の変数や戻りアドレス等が割り当てられます。 ここに 4MB 近くの領域を割り当てていますから正常に動作できません。 > short *data = (short *)malloc(sizeof(short)*N); のようにヒープ領域に確保(free() が必要)するか short data[N]; を関数外に記述するか、関数内であれば static short data[N]; と static 修飾して静的記憶域に確保しましょう。

ThanksImg質問者からのお礼コメント

ありがとうございます!

お礼日時:9/22 11:58

その他の回答(3件)

0

>N=2048000 平たく言うと「Nがデカすぎ」です もう少しNが小さいと上手く行きます

0

スタック領域のサイズはそんなに巨大ではないからです。 あなたは「スタックオーバーフロー」という超危険な事象を引き起こしてしまったのです。実行結果はともかくとして、システムや他のプログラムに悪影響を与えずに当該プログラムが終了しただけでも幸運です。

0

short data[N] の様にして宣言された配列は、メモリの中のスタック領域という場所に確保されます。 これは、ローカル変数や関数の呼び出しなんかに使われる領域なのですが、 この領域にはあまり沢山のメモリが割り当てられていません。 その為、そこに巨大な配列を作ろうとすると、スタック領域のメモリを使い果たしてしまいます。 malloc等で動的に確保した場合には、ヒープ領域と呼ばれる別のメモリエリアが使われます。 こちらは十分に広いサイズがあるので、巨大なデータも扱うことができます。 大きなデータを扱う場合には、こちらを使うようにして下さい。