1. ホーム
  2. c

配列型とmallocで確保された配列の違い

2023-12-19 13:22:41

疑問点

今日、私は友人のCコードを手伝っていたのですが、いくつかの奇妙な動作を発見し、それがなぜ起こっているのか彼に説明することができませんでした。私たちは整数のリストを含むTSVファイルを持っていて、その中に int という行があります。最初の行はリストが持っている行数でした。

また、非常に単純な "readfile" を持つ c ファイルがありました。最初の行は、読み込まれた n という初期化、行数の指定がありました。

int list[n]

で、最後にforループで n というループで fscanf .

小さな n (~100.000 まで) では、すべてがうまくいきました。しかし、n が大きいとき (10^6) には、セグメンテーション フォルトが発生することがわかりました。

最後に、私たちはリストの初期化を

int *list = malloc(n*sizeof(int))

で、うまくいくと、非常に大きな n .

なぜこのようなことが起こったのか、誰か説明してください。 int list[n] を使用し始めると停止しました。 list = malloc(n*sizeof(int)) ?

どのように解決するのですか?

ここでは、いくつかの異なる要素が絡み合っています。

1つ目は、配列を

int array[n];

int* array = malloc(n * sizeof(int));

最初のバージョンでは、自動保存期間を持つオブジェクトを宣言しています。 これは、配列を呼び出す関数が存在する限り、配列が生き続けることを意味します。 2番目のバージョンでは、動的な保存期間を持つメモリを取得しています。 free .

ここで2番目のバージョンが動作する理由は、Cが通常どのようにコンパイルされるかの実装の詳細です。 通常、C 言語のメモリは、スタック (関数呼び出しとローカル変数用) とヒープ (関数呼び出しとローカル変数用) を含むいくつかの領域に分割されます。 malloc オブジェクト)。 スタックは通常、ヒープよりもはるかに小さいサイズであり、通常は8MBといったところです。 その結果、巨大な配列を

int array[n];

そうすると、スタックの記憶領域を超えてしまい、セグメンテーションフォールトが発生する可能性があります。 一方、ヒープは通常巨大なサイズ(例えば、システム上で空いているスペースと同じだけ)を持っていますので malloc を使用してもメモリ不足のエラーは発生しません。

一般に、C言語では可変長配列には注意が必要です。

を使うようにしましょう。

これが役に立つといいのですが。