#define HUGE_NUMBER ???
char string[HUGE_NUMBER];
do_something_with_the_string(string);
潜在的なメモリの問題やバッファオーバーフローなどのリスクを冒すことなく、char配列に追加できる最大数は何だろうと思っていました。私はそれにユーザー入力を取得したいと思っていました。
Jack Kleinによるこの応答を参照してください( 元の投稿 を参照):
元のC標準(ANSI 1989/ISO 1990)では、コンパイラーが環境制限のセットの少なくとも1つの例を含む少なくとも1つのプログラムを正常に変換する必要がありました。これらの制限の1つは、少なくとも32,767バイトのオブジェクトを作成できることでした。
この最小制限は、1999年のC標準の更新で少なくとも65,535バイトに引き上げられました。
そのサイズより大きいオブジェクトを提供するためのC実装は必要ありません。つまり、(int)(65535/sizeof(int))より大きいintの配列を許可する必要はありません。
非常に実際的に言えば、現代のコンピューターでは、アレイをどのくらいの大きさで作成できるかを前もって言うことはできません。コンピュータにインストールされている物理メモリの量、OSによって提供される仮想メモリの量、すでに実行されている他のタスク、ドライバ、プログラムの数、使用しているメモリの量などに依存します。そのため、プログラムは昨日使用したメモリよりも今日実行しているメモリを多かれ少なかれ使用できる可能性があります。そうしないと、明日も使用できるようになります。
多くのプラットフォームでは、自動オブジェクト、つまり 'static'キーワードを使用せずに関数内で定義されたものに最も厳しい制限を課しています。一部のプラットフォームでは、静的な配列または動的な割り当てによって、より大きな配列を作成できます。
ここで、少し調整された回答を提供するために、バッファオーバーフローを回避するために巨大なアレイを宣言しないでください。これは、Cで考えられる最悪の習慣に近いものです。むしろ、適切なコードを作成するために時間をかけ、バッファオーバーフローが発生しないように注意してください。また、配列のサイズが事前にわからない場合は、malloc
を参照してください。これは便利です:P
char string[HUGE_NUMBER];
が配置されます。
関数内ですか?次に、アレイはスタック上にあり、ifおよびどのくらい速く OSがスタックを拡張できるかは、OSによって異なります。したがって、ここに一般的なルールがあります。スタックに巨大な配列を配置しないでください。
それが関数を追い出している場合、それはグローバル(プロセスメモリ)です。OSがプログラムをロードしようとしたときにメモリを多く割り当てることができない場合、プログラムはクラッシュし、プログラムはそれに気付く機会がありません(以下はより良い:)
大規模な配列はmalloc
する必要があります。 mallocを使用すると、malloc
が失敗した場合、OSはnullポインターを返します。これは、OSとそのページングスキーマおよびメモリマッピングスキーマに応じて、1)連続した空き領域がない場合に失敗します。アレイに十分な大きさのメモリ、または2)OSは、連続物理メモリとしてプロセスに表示されるメモリに、空き物理メモリの十分な領域をマップできません。
だから、大きな配列でこれを行います:
char* largeArray = malloc(HUGE_NUMBER);
if(!largeArray) { do error recovery and display msg to user }
バッファオーバーフローを回避するために任意の巨大な配列を宣言することは悪い習慣です。バッファーの大きさが事前に本当にわからない場合は、malloc
またはrealloc
を使用して、必要に応じて動的にバッファーを動的に割り当て、拡張します。仲介者として。
例:
#define PAGE_SIZE 1024 // 1K buffer; you can make this larger or smaller
/**
* Read up to the next newline character from the specified stream.
* Dynamically allocate and extend a buffer as necessary to hold
* the line contents.
*
* The final size of the generated buffer is written to bufferSize.
*
* Returns NULL if the buffer cannot be allocated or if extending it
* fails.
*/
char *getNextLine(FILE *stream, size_t *bufferSize)
{
char input[PAGE_SIZE]; // allocate
int done = 0;
char *targetBuffer = NULL;
*bufferSize = 0;
while (!done)
{
if(fgets(input, sizeof input, stream) != NULL)
{
char *tmp;
char *newline = strchr(input, '\n');
if (newline != NULL)
{
done = 1;
*newline = 0;
}
tmp = realloc(targetBuffer, sizeof *tmp * (*bufferSize + strlen(input)));
if (tmp)
{
targetBuffer = tmp;
*bufferSize += strlen(input);
strcat(targetBuffer, input);
}
else
{
free(targetBuffer);
targetBuffer = NULL;
*bufferSize = 0;
fprintf(stderr, "Unable to allocate or extend input buffer\n");
}
}
}
配列がスタックに割り当てられる場合、スタックサイズによって制限されます( 通常Windowsでは1MB 、一部が使用されるため、さらに少なくなります)。それ以外の場合は、制限がかなり大きくなると思います。
ただし、配列を本当に大きくすることは、バッファオーバーフローの問題の解決策ではありません。しないでください。使用するバッファーの量を制限するメカニズムを持つ関数を使用して、バッファーをオーバーステップしないようにし、サイズをより適切なものにします(たとえば1K)。
malloc()
を使用すると、通常の配列で処理できるよりも大きな部分のメモリを取得できます。
まあ、バッファオーバーフローはHUGE_NUMBERの値が大きすぎても、書き込まれた値に比べて小さすぎても(インデックスHUGE_NUMBER以上に書き込んだら、バッファがオーバーフローしたため)発生しません。
それはさておき、それはマシンに依存します。確かに、ヒープ内で数百万、スタック上で100万程度を処理できるシステムがあります(他の圧力によって異なります)が、数百を超えて処理できないシステムもあります(小さな組み込みデバイスは明白な例)。 65,535は標準で指定された最小値ですが、非常に小さいデバイスは、この理由で標準が意図的に逸脱したと指定できます。
実際には、大規模なマシンでは、実際にメモリが不足するずっと前に、パフォーマンスに影響を与えるような方法でメモリを不必要に圧迫しています。配列を適切なサイズに動的にサイズ変更することをお勧めします。