C ライブラリの calloc() 関数とプログラム例
⚡ スマートサマリー
C言語のcalloc()関数は、ヒープ上に複数の連続したメモリブロックを予約し、すべてのバイトをゼロで初期化して、プログラムが実行時にクリーンですぐに使用できる配列やデータ構造を作成できるようにするvoidポインタを返します。
C の calloc とは何ですか?
C言語のcalloc()関数は、同じサイズの複数のメモリブロックを割り当てるために使用されます。これは動的メモリ割り当て関数であり、配列や構造体などの複雑なデータ構造にメモリ領域を割り当て、メモリへのvoidポインタを返します。callocは「連続割り当て」の略です。
Malloc関数 はメモリ空間の単一ブロックを割り当てるために使用され、C の calloc 関数はメモリ空間の複数のブロックを割り当てるために使用されます。 C プログラミングの calloc によって割り当てられる各ブロックは同じサイズです。
C言語でcalloc()を使う理由とは?
通常の変数や固定サイズの配列は、プログラムのコンパイル時にそのサイズが固定されるため、必要な要素数が少ない場合はメモリが無駄になり、必要な要素数が多い場合は処理が失敗します。calloc() は、実行時にメモリを確保することでこの制限を取り除き、malloc() とは異なり、ブロックを返す前にすべてのバイトをゼロにクリアします。そのため、配列や構造体のサイズがコードの実行中にしか分からない場合、プログラムがクリーンで予測可能なメモリ領域を必要とする際には、calloc() が最適な選択肢となります。
calloc() による動的メモリ割り当ては、いくつかの一般的な状況に適しています。
- カウンター、ヒストグラム、累積値など、ゼロから開始する必要がある数値配列。
- 残りのゴミ値が微妙で捉えにくい問題を引き起こすデータ構造tracそしてバグ。
- Bufferプログラムの実行中にユーザー入力または読み込まれたファイルによって長さが変わるs。
- ブロックが大きすぎて限られたスタックに収まらないのは、calloc() がはるかに大きなヒープからデータを取得するためです。
予約されたブロックは連続しており、既にゼロで初期化されているため、別途初期化ループを経ることなく、すぐに使用可能な配列として扱うことができます。
calloc() 構文:
ptr = (cast_type *) calloc (n, size);
- C での calloc の上記のステートメントの例は、同じサイズの n 個のメモリ ブロックを割り当てるために使用されます。
- メモリ空間が割り当てられた後、すべてのバイトがゼロに初期化されます。
- その ポインタ 現在、割り当てられたメモリ空間の最初のバイトにあるものが返されます。
メモリ不足など、メモリ空間の割り当てでエラーが発生した場合は、次の calloc の例に示すように null ポインタが返されます。
callocの使い方
以下の C の calloc プログラムは、等差数列の合計を計算します。
#include <stdio.h> int main() { int i, * ptr, sum = 0; ptr = calloc(10, sizeof(int)); if (ptr == NULL) { printf("Error! memory not allocated."); exit(0); } printf("Building and calculating the sequence sum of the first 10 terms \ n "); for (i = 0; i < 10; ++i) { * (ptr + i) = i; sum += * (ptr + i); } printf("Sum = %d", sum); free(ptr); return 0; }
C での calloc の結果の例:
Building and calculating the sequence sum of the first 10 terms
Sum = 45
calloc() と malloc() の違い
calloc() と malloc() はどちらもヒープ上にメモリを予約し、どちらも void ポインタ、または失敗した場合は NULL を返しますが、どちらを使用するかを決定する 3 つの実用的な点で異なります。
- 初期化: calloc() は新しいブロック内のすべてのバイトをゼロに設定しますが、malloc() は内容を初期化しないままにするため、malloc() ブロックにはプログラムが書き込むまで予測不可能なゴミデータが格納されます。
- 引数: calloc() は要素数と各要素のサイズという 2 つの引数を取ります (calloc(n, size) と表記)。malloc() は合計バイト数という 1 つの引数を取ります (malloc(n * size) と表記)。
- 速度:malloc() はゼロクリアのステップを省略するため、わずかに高速です。そのため、メモリを即座に上書きするコードは、malloc() を好んで使用することがよくあります。
どちらの関数もstdlib.hで宣言されており、どちらも同じfree()関数でメモリを解放します。クリーンなゼロブロックが必要な場合はcalloc()を、速度が重視され、プログラムが初期化を自身で処理する場合はmalloc()を選択してください。
calloc() で割り当てられたメモリを解放する方法
calloc() で確保されたメモリはヒープ上に存在し、自動的に解放されることはありません。プログラムが解放せずにメモリ割り当てを続けると、利用可能なメモリを徐々に消費してしまいます。これはメモリリークと呼ばれる不具合です。free() 関数は、使用済みのブロックをシステムに返すことで、その領域を後続の割り当てで再利用できるようにします。
free() 関数は、calloc() が返したポインタを引数として受け取り、ブロック全体を一度に解放します。
int *ptr; ptr = calloc(10, sizeof(int)); if (ptr != NULL) { /* use the allocated memory here */ free(ptr); /* release the block */ ptr = NULL; /* avoid a dangling pointer */ }
calloc() でメモリを安全に管理するには、以下のルールに従ってください。
- calloc()が成功するたびに、free()を必ず1回だけ呼び出してください。同じブロックを2回解放すると、未定義の動作が発生します。
- 解放後にポインタをNULLに設定することで、ダングリングポインタとして再利用されるのを防ぎます。
- calloc() が返さなかったポインタ(ポインタ演算によってシフトされたものを含む)を free() で解放してはいけません。
- ポインタがスコープ外になる前に、すべての割り当てを解放と対応させてください。
calloc() と malloc() はどちらも同じヒープからデータを取得するため、解放処理はどちらの関数でも同じです。つまり、割り当てが成功するたびに free() が呼び出され、その後はブロックにアクセスできなくなります。ping メモリの割り当てと解放をバランスよく行うことは、C言語における手動メモリ管理の核となる習慣であり、メモリリークと、既に解放されたメモリを再利用することによって引き起こされるクラッシュの両方を防ぎます。

