C ライブラリの malloc() 関数と例

⚡ スマートサマリー

C言語のmalloc()関数は、実行時にヒープ上にメモリブロックを予約し、その最初のバイトへのvoidポインタを返します。これにより、プログラムはコードが実際に実行されるまでサイズが不明なストレージを要求できます。

  • 🧠 実行時割り当て: malloc() は、コンパイル時に必要なメモリサイズが不明な場合に、実行中にメモリを確保します。
  • 📦 構文: cast_type ポインタは malloc(byte_size) を受け取ります。移植性のために、通常は sizeof でサイズが指定されます。
  • ⚠️ NULLチェック: リクエストが失敗するとNULLポインタが返されるため、結果を逆参照する前に検証してください。
  • ポインタ演算: ブロックは連続しているので、配列要素にアクセスするには++ではなく+を使用してください。
  • 🧹 メモリを解放する: メモリリークやダングリングポインタを防ぐため、すべてのブロックをfree()で解放してください。
  • 🤖 AI支援: AIアシスタントとGitHub Copilotはmalloc()呼び出しをドラフトし、free()ステートメントが欠落していることを指摘します。

C言語のmalloc()関数

Cのmallocとは何ですか?

malloc() 関数はメモリ割り当てを表します。 これは、メモリのブロックを動的に割り当てるために使用される関数です。 指定されたサイズのメモリ空間を予約し、メモリ位置を指す null ポインタを返します。 返されるポインタは通常、void 型です。 これは、malloc 関数を任意のポインターに割り当てることができることを意味します。

Cの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()関数でメモリを解放します。

よくあるご質問

C言語では、キャストはオプションであり、多くの場合推奨されません。なぜなら、void*は自動的に任意のオブジェクトポインタに変換され、明示的なキャストはstdlib.hのインクルードの欠落を隠蔽する可能性があるからです。 C++ただし、出演者が必要です。

NULLが返された場合は、要求が失敗したことを意味します。通常はメモリ不足が原因です。ポインタを使用する前に必ずポインタを確認してください。NULLを逆参照すると未定義の動作が発生し、通常はプログラムがクラッシュします。

realloc() は、以前に malloc() によって予約されたブロックのサイズを変更します。ping より小さいサイズまでの既存データ。失敗した場合はNULLを返し、元のブロックはそのまま残るため、まずその結果を一時ポインタに代入してください。

メモリリークは、malloc() で確保したヒープメモリが free() で解放されない場合に発生します。プログラムはもはや使用しない領域を確保し続け、徐々に利用可能なメモリを使い果たしてしまう可能性があります。

malloc() はスタックではなくヒープ上にメモリを確保します。ヒープブロックは free() を呼び出すまで有効なままなので、作成した関数よりも長く存続します。これは、戻り値とともに消滅する自動スタック変数とは異なります。

malloc() は void* を返すライブラリ関数であり、バイト数を計算するために sizeof を必要とします。 C++ new は、型付きポインタを返し、コンストラクタを呼び出す演算子です。malloc() と free()、new と delete を対応させてください。

はい。AIコーディングアシスタントはmalloc()呼び出しを生成し、NULLチェックを挿入し、free()呼び出しの欠落やメモリリークを指摘し、ポインタ演算の説明もできます。生成されたコードを信頼する前に、必ずコンパイルしてテストしてください。

GitHubコパイロット 意図を説明するコメントから、malloc()、sizeof()、および対応するfree()の行を提案します。 Revコンパイルする前に、NULLチェックの欠落やメモリリークに関する各提案を確認してください。