C言語 動的メモリ確保: malloc, calloc, realloc, free をマスターする
C言語における動的メモリ確保
このガイドでは、標準ライブラリ関数malloc()、calloc()、realloc()、free()を用いたC言語の動的メモリ確保を、明確な例とベストプラクティスとともに解説します。
なぜ動的確保を使うのか?
静的配列はコンパイル時に固定サイズで宣言されるため、実行時に無駄なスペースが生じたり、容量不足になったりします。動的確保なら、プログラム実行中に必要なメモリ量を正確に要求できます。
これら4関数はすべて<stdlib.h>ヘッダで定義され、ヒープメモリを制御された方法で管理します。
malloc() – バイトブロックを確保
mallocは「memory allocation」の略です。指定サイズ(バイト単位)の連続したメモリブロックを確保し、任意のポインタ型にキャスト可能なvoid *型ポインタを返します。
構文
ptr = malloc(size_in_bytes); // 必要なら目的の型にキャスト
例
float *ptr = malloc(100 * sizeof(float)); // 一般的なシステムで400バイト
ここでは、ptrが400バイトブロックの先頭バイトを指します。要求が失敗するとmallocはNULLを返します。C言語では不要なキャストは避けるのが推奨されます。型付きポインタに代入する際、コンパイラが型を推論できます。
calloc() – 確保とゼロ初期化
callocは「contiguous allocation」の略。mallocと異なり、確保したブロックの全ビットをゼロで初期化するため、数値型やポインタに対して安全です。
構文
ptr = calloc(num_elements, size_of_each_element);
例
float *ptr = calloc(25, sizeof(float)); // 25個のゼロ初期化されたfloat要素
確保失敗時はNULLが返されます。
free() – 確保メモリの解放
mallocやcallocで取得したメモリは、明示的に解放するまで持続します。free()はブロックを解放し、メモリをヒープに返却して再利用可能にします。
構文
free(ptr);
NULLポインタに対するfree呼び出しは安全で、何もしません。
例1: malloc()とfree()の使用
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n, i, *ptr, sum = 0;
printf("要素数を入力: ");
scanf("%d", &n);
ptr = malloc(n * sizeof(int));
if (!ptr) {
fprintf(stderr, "Error: memory not allocated.\n");
return EXIT_FAILURE;
}
printf("要素を入力: ");
for (i = 0; i < n; ++i) {
scanf("%d", ptr + i);
sum += *(ptr + i);
}
printf("Sum = %d\n", sum);
free(ptr);
return EXIT_SUCCESS;
}
出力
要素数を入力: 3
要素を入力: 100 20 36
Sum = 156
例2: calloc()とfree()の使用
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n, i, *ptr, sum = 0;
printf("要素数を入力: ");
scanf("%d", &n);
ptr = calloc(n, sizeof(int));
if (!ptr) {
fprintf(stderr, "Error: memory not allocated.\n");
return EXIT_FAILURE;
}
printf("要素を入力: ");
for (i = 0; i < n; ++i) {
scanf("%d", ptr + i);
sum += *(ptr + i);
}
printf("Sum = %d\n", sum);
free(ptr);
return EXIT_SUCCESS;
}
出力
要素数を入力: 3
要素を入力: 100 20 36
Sum = 156
realloc() – 既存確保のリサイズ
現在の確保が小さすぎる、または大きすぎることが判明した場合、realloc()は既存データを保持したまま(新サイズまで)サイズを調整します。
構文
ptr = realloc(ptr, new_size_in_bytes);
再確保されたブロックへのポインタ、または失敗時NULLを返します。メモリリークを防ぐため、結果を一時ポインタにまず格納してください。
例3: realloc()の使用
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *ptr, i, n1, n2;
printf("初期サイズを入力: ");
scanf("%d", &n1);
ptr = malloc(n1 * sizeof(int));
if (!ptr) {
fprintf(stderr, "Allocation failed.\n");
return EXIT_FAILURE;
}
printf("再確保前のアドレス:\n");
for (i = 0; i < n1; ++i) printf("%p\n", ptr + i);
printf("\n新サイズを入力: ");
scanf("%d", &n2);
int *tmp = realloc(ptr, n2 * sizeof(int));
if (!tmp) {
fprintf(stderr, "Reallocation failed.\n");
free(ptr);
return EXIT_FAILURE;
}
ptr = tmp;
printf("再確保後のアドレス:\n");
for (i = 0; i < n2; ++i) printf("%p\n", ptr + i);
free(ptr);
return EXIT_SUCCESS;
}
典型的な出力
初期サイズを入力: 2
再確保前のアドレス:
0x7ffc12345670
0x7ffc12345674
新サイズを入力: 4
再確保後のアドレス:
0x7ffc12345670
0x7ffc12345674
0x7ffc12345678
0x7ffc1234567c
これら4関数をマスターし、適切なエラーハンドリングを適用することで、あらゆるCアプリケーションでヒープメモリを安全かつ効率的に管理できます。
C言語
- ROM、PROM、EPROM、EEPROMの理解:設計、プログラミング、識別
- マイクロプロセッサ:ストアドプログラムコンピューティングの進化
- ダイナミックプライシングが伝統小売に回帰:なぜそれは不可避なのか
- Cervoz、産業用AIおよびIoTソリューション向け高度DDR4-2666メモリを発売
- C++メモリ管理の極意:newとdeleteのエキスパート活用法
- C++動的配列の確保をマスター:コード例付き実践ガイド
- C言語のcalloc():ゼロ初期化メモリ割り当てと実践例
- C言語のrealloc()活用ガイド:構文、ベストプラクティス、実例
- C言語動的メモリ管理:calloc、malloc、freeの解説
- C++動的メモリ管理完全解説:スタックとヒープ、new/delete
- Java 10でヒープをNV-DIMMに割り当て:-XX:AllocateHeapAtオプション