9

可変長配列がサポートされる前は、次のように動的に割り当てていました。

int foo(size_t n)
{
    int *arr = malloc(n * sizeof int);
    if (!arr) return ENOMEM; /* not enough memory */
    .
    . else do stuff with arr[]
    .
    free(arr);
    return 0;
}

可変長配列を使用すると、見栄えを良くすることができます。

int bar(size_t n)
{
    int arr[n];
    .
    . do stuff with arr[]
    .
    return 0;
}

しかし、今は「メモリ不足」のチェックはありません。実際、nが大きすぎると、プログラムがクラッシュします。

nが大きすぎる場合、どうすればbar(n)から優雅に保釈できますか?

4

3 に答える 3

12

状況は他のローカル変数とまったく変わりません-次のような宣言:

int baz(void)
{
    int arr[100000];
    .
    . do stuff with arr[]
    .
    return 0;
}

まったく同じ問題があります。「解決策」はこれまでと同じです。繰り返しを深くしすぎたり、自動保存期間で非常に大きなデータ構造を割り当てたりしないでください(malloc()これらの場合は引き続き使用してください)。「非常に大きい」の値は、環境によって大きく異なります。

言い換えると、それが妥当な値に制限されint array[n];ていることがわかっている場合を除いて、宣言しないでください。そのnため、その最大サイズの配列を、通常の、変更されない型の配列として宣言できます。

(はい、これは、必要な最大サイズで配列を宣言するだけではほとんど得られないため、可変的に変更された型配列は最初に表示されるほど有用ではないことを意味します)。

于 2010-11-11T03:41:56.863 に答える
6

使用しないことでクラッシュを防ぐことができます。:)

真面目な話ですが、サイズに強い制限がない限り、可変長配列を使用して作業を楽にする安全な方法はほとんどありません。一方、次のように条件付きで使用できます。

char vla_buf[n < 1000 ? n : 1];
char *buf = sizeof vla_buf < n ? malloc(n) : vla_buf;
if (!buf) goto error;
/* ... Do stuff with buf ... */
if (buf != vla_buf) free(buf);

これは役に立たない苦痛のように見えますが、特に多くの呼び出しが行われ、ロックの競合が発生する可能性があるスレッド化されたアプリケーションでは、パフォーマンスに大きな違いmallocfree生じる可能性があります。(このトリックの注目すべき副次的な利点は、マクロなどに置き換えるだけ[n < 1000 ? n : 1]1000、VLAなしで古いコンパイラをサポートできることです。)

VLAが役立つ可能性のあるもう1つのあいまいなケースは、再帰アルゴリズムの場合です。再帰アルゴリズムでは、再帰のすべてのレベルで必要な配列エントリの総数がによって制限されます。nここでnは、スタックがオーバーフローしないと確信できるほど小さいですが、最大の再帰レベルと、最大の要素nを使用する個々のレベルである可能性があります。nC99より前は、n^2スタックスペースを使用せずにこのケースを処理する唯一の方法は、を使用することでしたmalloc。VLAを使用すると、スタック上で問題を完全に解決できます。

VLAが本当に有益であるこれらのケースは、非常にまれであることに注意してください。通常、VLAは、作成した(悪用するのが簡単な)脆弱性に気付くまで、メモリ管理が簡単であると自分自身を欺く方法にすぎません。:-)

編集: OPの元の質問によりよく対処するには:

#define MAX_VLA 10000
int bar(size_t n)
{
    int arr[n <= MAX_VLA ? n : 1];
    if (sizeof arr/sizeof *arr < n) return ENOMEM;
    /* ... */
    return 0;
}
于 2010-11-11T03:53:13.147 に答える
0

実際には、どこでもメモリ不足の状態をチェックするのは非常に費用がかかります。大量のデータを処理するための積極的な方法は、単一の初期チェックポイントでサイズにハードキャップを定義することによってデータサイズを制限し、キャップに達したときに迅速かつ適切に失敗することです。

私が今提案したのは単純で愚かなことです。しかし、それはすべての通常の(非科学的または特別な)製品が常に行うことです。そして、それは通常顧客が期待するものです。

于 2010-11-11T05:23:57.660 に答える