C ライブラリの malloc() 関数と例
⚡ スマートサマリー
C言語のmalloc()関数は、実行時にヒープ上にメモリブロックを予約し、その最初のバイトへのvoidポインタを返します。これにより、プログラムはコードが実際に実行されるまでサイズが不明なストレージを要求できます。
Cのmallocとは何ですか?
malloc() 関数はメモリ割り当てを表します。 これは、メモリのブロックを動的に割り当てるために使用される関数です。 指定されたサイズのメモリ空間を予約し、メモリ位置を指す null ポインタを返します。 返されるポインタは通常、void 型です。 これは、malloc 関数を任意のポインターに割り当てることができることを意味します。
構文
ptr = (cast_type *) malloc (byte_size);
ここでは、
- ptr は、cast_type のポインタです。
- malloc 関数は、byte_size の割り当てられたメモリへのポインタを返します。
Example: ptr = (int *) malloc (50)
このステートメントが正常に実行されると、50 バイトのメモリ空間が予約されます。 予約領域の最初のバイトのアドレスは、int 型のポインタ ptr に割り当てられます。
malloc 実装の別の例を考えてみましょう。
#include <stdlib.h> int main(){ int *ptr; ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */ if (ptr != NULL) { *(ptr + 5) = 480; /* assign 480 to sixth integer */ printf("Value of the 6th integer is %d",*(ptr + 5)); } }
出力:
Value of the 6th integer is 480
*ptr 宣言が後で別のデータ型に型キャストされた場合にコードの堅牢性を高めるため、sizeof(int) の代わりに sizeof(*ptr) が使用されていることに注意してください。
メモリが十分でない場合、割り当てが失敗する可能性があります。 この場合、NULL ポインタが返されます。 したがって、NULL ポインターをチェックするコードを含める必要があります。
割り当てられたメモリは連続しており、配列として扱うことができることに注意してください。 ポインタ 角括弧 [ ] を使用する代わりに、算術演算子を使用して配列要素にアクセスしてください。インクリメント ++ や += を使用するとポインタに格納されているアドレスが変更されるため、配列要素を参照するには + を使用することをお勧めします。
Malloc 関数は、構造体などの複雑なデータ型だけでなく、文字データ型でも使用できます。
C言語でmalloc()を使う理由とは?
静的配列と通常の変数は、プログラムのコンパイル時にサイズが固定されるため、必要なサイズが小さくなった場合はスペースが無駄になり、大きくなった場合は完全に失敗します。malloc() は実行時にメモリを要求することでこの問題を解決し、プログラムが受け取るデータ量に合わせてバッファのサイズを正確に設定できるようにします。この実行時の柔軟性が、 動的メモリ割り当て Cで。
malloc() を使用した動的割り当ては、いくつかの一般的な状況において適切な選択肢となります。
- 入力されるデータの量は、ファイルやユーザーが指定したリストを読み込むなど、プログラムが実行されるまで不明です。
- malloc() ははるかに大きなヒープからデータを取得するため、限られたスタックではオーバーフローするほど大きなブロックが必要になります。
- データは、それを作成した関数よりも長く存続しなければならない。なぜなら、ヒープメモリは明示的に解放されるまで保持されるからである。
- プログラムの実行中に、構造体や配列のサイズは拡大縮小する必要がある。
予約されたブロックはポインタとして返されるため、基となるデータをコピーすることなく、関数間で低コストで受け渡すことができる。
malloc() で割り当てられたメモリを解放する方法
malloc() で確保されたメモリはヒープ上に存在し、自動的に解放されることはありません。プログラムが解放せずにメモリを割り当て続けると、利用可能なメモリを徐々に消費してしまいます。これはメモリリークと呼ばれる不具合です。free() 関数は、使用済みのブロックをシステムに返すことで、その領域を再利用できるようにします。
free() 関数は、malloc() が返したポインタを引数として受け取り、ブロック全体を一度に解放します。
int *ptr; ptr = malloc(10 * sizeof(int)); if (ptr != NULL) { /* use the allocated memory here */ free(ptr); /* release the block */ ptr = NULL; /* avoid a dangling pointer */ }
動的メモリを安全に管理するには、以下のルールに従ってください。
- malloc()が成功するたびに、free()を必ず1回だけ呼び出してください。同じブロックを2回解放すると、未定義の動作が発生します。
- 解放後にポインタをNULLに設定することで、ダングリングポインタとして再利用されるのを防ぎます。
- malloc() が返さなかったポインタ(ポインタ演算によってシフトされたものを含む)を free() で解放してはいけません。
- ポインタがスコープ外になる前に、すべての割り当てを対応する解放と照合してください。
キーping メモリの割り当てと解放のバランスを取ることは、C言語における手動メモリ管理の中核となる規律であり、解放されたメモリの再利用によって引き起こされるメモリリークとクラッシュの両方を防ぐ。
malloc()とcalloc():主な違い
malloc() と calloc() どちらもヒープメモリを予約しますが、引数と新しいブロックの扱い方が異なります。malloc() は合計バイト数という 1 つの引数を取り、内容を初期化しないままにしておくため、プログラムが書き込むまでブロックには予測不可能なガベージ値が格納されます。calloc() は要素数と各要素のサイズという 2 つの引数を取り、ポインタを返す前にすべてのバイトをゼロにクリアします。
実際的な違いは、主に次の3点に集約されます。
- 初期化:calloc() はメモリをゼロクリアしますが、malloc() はゼロクリアしないため、値がいずれ上書きされる場合は malloc() の方がわずかに高速です。
- 引数: malloc(n * size) と記述しますが、同じ配列を予約するには calloc(n, size) を使用します。
- 使用例:クリーンでゼロで初期化されたブロックが重要な場合はcalloc()を選択し、速度が優先され、初期化を手動で行う場合はmalloc()を選択します。
どちらの関数もstdlib.hで宣言されており、失敗した場合はどちらもvoidポインタまたはNULLを返し、どちらも同じfree()関数でメモリを解放します。


