web-dev-qa-db-ja.com

Cでmallocを使用する必要があるのはいつですか?

Malloc()の仕組みを理解しています。私の質問は、次のようなものが表示されます。

#define A_MEGABYTE (1024 * 1024)

char *some_memory;
size_t size_to_allocate = A_MEGABYTE;
some_memory = (char *)malloc(size_to_allocate);
sprintf(some_memory, "Hello World");
printf("%s\n", some_memory);
free(some_memory);

簡潔にするため、エラーチェックは省略しました。私の質問は、メモリ内の静的ストレージへのポインタを初期化するだけで上記のことを行うことはできませんか?おそらく:

char *some_memory = "Hello World";

保持する必要がある値を宣言/初期化するのではなく、実際にどの時点でメモリを自分で割り当てる必要がありますか?

90
randombits
char *some_memory = "Hello World";

文字列定数へのポインタを作成しています。つまり、文字列「Hello World」はメモリの読み取り専用部分のどこかにあり、ポインタを持っているだけです。文字列を読み取り専用として使用できます。あなたはできませんに変更を加えます。例:

some_memory[0] = 'h';

トラブルを求めています。

一方

some_memory = (char *)malloc(size_to_allocate);

はchar配列(変数)を割り当てており、some_memoryはその割り当てられたメモリを指します。現在、この配列は読み取りと書き込みの両方です。次のことができます。

some_memory[0] = 'h';

配列の内容が「hello World」に変わります

128
codaddict

その正確な例では、mallocはほとんど役に立ちません。

Mallocが必要な主な理由は、コードスコープとは異なる有効期間を持つ必要があるデータがある場合です。コードは1つのルーチンでmallocを呼び出し、ポインターをどこかに保存し、最終的に別のルーチンでfreeを呼び出します。

2番目の理由は、Cには、割り当てのためにスタックに十分なスペースが残っているかどうかを知る方法がないためです。コードを100%堅牢にする必要がある場合は、mallocを使用する方が安全です。コードは割り当てが失敗したことを認識して処理できるためです。

36

mallocは、コンパイル時に処理されるためサイズを変更できないhello worldの例のような静的宣言と比較して、実行時にメモリを割り当て、再割り当て、解放するための素晴らしいツールです。

したがって、Mallocは、ファイルの内容の読み取りやソケットの処理など、任意のサイズのデータ​​を処理し、処理するデータの長さを認識していない場合に常に役立ちます。

もちろん、あなたが与えたような些細な例では、mallocは魔法の「適切な仕事のための適切なツール」ではありませんが、より複雑な場合(例えば、実行時に任意のサイズの配列を作成する)、それが唯一の方法です行く。

15
moritz

使用する必要があるメモリの正確なサイズがわからない場合は、動的割り当て(malloc)が必要です。例は、ユーザーがアプリケーションでファイルを開いたときです。ファイルの内容をメモリに読み込む必要がありますが、実行時にユーザーがその場でファイルを選択するため、もちろんファイルのサイズは事前にはわかりません。したがって、基本的には、事前に作業しているデータのサイズがわからないときにmallocが必要です。少なくとも、それがmallocを使用する主な理由の1つです。コンパイル時のサイズがすでにわかっている単純な文字列を使用した例では(さらに、変更したくない場合)、動的に割り当てることはあまり意味がありません。


少しトピックから外れていますが、... mallocを使用するときにメモリリークが発生しないように非常に注意する必要があります。次のコードを検討してください。

int do_something() {
    uint8_t* someMemory = (uint8_t*)malloc(1024);

    // Do some stuff

    if ( /* some error occured */ ) return -1;

    // Do some other stuff

    free(someMemory);
    return result;
}

このコードの何が問題なのかわかりますか? mallocfreeの間に条件付きreturnステートメントがあります。最初は問題ないと思われるかもしれませんが、考えてみてください。エラーが発生した場合は、割り当てたメモリを解放せずに戻ります。これは、メモリリークの一般的な原因です。

もちろん、これは非常に単純な例であり、ここで間違いを見つけるのは非常に簡単ですが、ポインター、mallocs、frees、およびあらゆる種類のエラー処理が散らばった数百行のコードを想像してください。 。物事は本当に速く非常に乱雑になる可能性があります。これは、適用可能な場合にCよりも現代のC++を好む理由の1つですが、それはまったく別のトピックです。

したがって、mallocを使用するときは常に、メモリがfreedである可能性が高いことを常に確認してください。

7
adam10603
char *some_memory = "Hello World";
sprintf(some_memory, "Goodbye...");

違法です、文字列リテラルはconstです。

これにより、スタック上またはグローバルに(宣言されている場所に応じて)12バイトのchar配列が割り当てられます。

char some_memory[] = "Hello World";

さらに操作する余地を残したい場合は、配列のサイズを大きくするように指定できます。 (ただし、スタックに1MBを入れないでください。)

#define LINE_LEN 80

char some_memory[LINE_LEN] = "Hello World";
strcpy(some_memory, "Goodbye, sad world...");
printf("%s\n", some_memory);
6
ephemient

メモリを割り当てる必要がある1つの理由は、実行時にメモリを変更する場合です。その場合、スタック上のmallocまたはバッファを使用できます。 「Hello World」をポインターに割り当てる簡単な例では、「通常」実行時に変更できないメモリを定義しています。

5
Mark Wilkins