表示テーマ
Memory — malloc / realloc / free
TL;DR
確保の失敗を確認し、所有者が不要になった領域を一度だけ free します。realloc の結果は一時ポインタで受けます。以下はISO C99以降、要求サイズが正の場合の例です。
Example
c
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
size_t count = 4;
int *values;
if (count > SIZE_MAX / sizeof *values) {
return EXIT_FAILURE;
}
values = malloc(count * sizeof *values);
if (values == NULL) {
return EXIT_FAILURE;
}
for (size_t i = 0; i < count; ++i) {
values[i] = (int)i;
}
size_t next_count = 8;
if (next_count > SIZE_MAX / sizeof *values) {
free(values);
return EXIT_FAILURE;
}
int *next = realloc(values, next_count * sizeof *values);
if (next == NULL) {
free(values); /* 正のサイズでの失敗時、元の領域は有効 */
return EXIT_FAILURE;
}
values = next;
for (size_t i = count; i < next_count; ++i) {
values[i] = 0;
}
printf("%d %d\n", values[3], values[7]); /* 3 0 */
free(values);
return EXIT_SUCCESS;
}Explanation
mallocで確保した内容は未初期化です。読む前に書き込みます。callocは確保領域の全ビットを0にします。あらゆる型の意味上のゼロやNULLポインタ表現を保証するものではありません。- 正のサイズで
reallocが失敗すると元の領域が残ります。成功したら返されたポインタを使い、元の領域を指していた別のポインタも使い続けないでください。 - Cでは
mallocの戻り値のキャストは不要です。<stdlib.h>の宣言は必要です。
Pitfalls
NGは values = realloc(values, bytes); と直接代入することです。失敗時に元のポインタを失うため、上の例のように一時変数で受けます。
所有権と寿命
二重解放、解放後の読み書き(use-after-free)は未定義動作です。free(NULL) は何もしませんが、解放後に1つの変数をNULLにしても、その領域を指す別のポインタは無効なままです。
要素数と要素サイズの積は、確保前にオーバーフローを確認します。ゼロサイズの確保・再確保には規格バージョンや処理系に依存する点があるため、この例では正のサイズだけを扱います。
Related
参考
C11委員会草案 N1570 §7.22.3。ゼロサイズの realloc を含む後続規格の変更を、この例の前提に混在させていません。