経緯
mallocでメモリを確保する方法はわかったものの,プログラム実行中に自動でメモリ管理するようにして使わないと意味なくない?と思い,ユーザの任意の入力文字列に合わせて動的にメモリ確保する方法を調べていた.
ChatGPTがgetcharで1文字ずつ受け取る例を出力したためそれに対して以下の質問をした.
質問:「getcharで1文字ずつ読み取らなければreallocによる動的メモリ範囲の拡張はできないのですか?」
以下はChatGPTの回答.
getchar
で1文字ずつ読み取らなくても、realloc
を使って動的メモリを拡張することは可能です。入力のサイズを事前に把握する必要はなく、例えば fgets
を使って一度にデータを読み取る場合でも、メモリの不足に応じて動的に拡張できます。
realloc
による動的メモリの拡張は、文字列を逐次的に受け取る(1文字ずつ、または一括で)方法に依存しません。重要なのは「メモリのサイズが不足した場合に、その都度メモリを再確保する」処理が必要である点です。
以下に、getchar
を使わず、fgets
や scanf
のような方法で、動的にメモリを拡張する実装例を紹介します。
例: fgets
を使って動的メモリを拡張
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char *input = NULL;
int buf_size = 10; // 初期バッファサイズ
int length = 0; // 入力文字列の長さ(ヌル文字を含む)
// メモリの動的確保
input = (char *)malloc(buf_size * sizeof(char));
if (input == NULL) {
printf("Memory allocation failed!\n");
return 1;
}
printf("Enter a string: ");
// 入力を一度に読み取るが、バッファが足りない場合には再確保
while (fgets(input + length, buf_size - length, stdin) != NULL) {
// 改行文字が含まれているか確認
length = strlen(input);
if (input[length - 1] == '\n') {
input[length - 1] = '\0'; // 改行をヌル文字に変換して終了
break; // 改行が含まれていたら入力終了
}
// バッファが足りなくなった場合にメモリを再確保
buf_size *= 2; // バッファサイズを倍増
input = (char *)realloc(input, buf_size);
if (input == NULL) {
printf("Memory reallocation failed!\n");
return 1;
}
}
printf("You entered: %s\n", input);
// 動的に確保したメモリを解放
free(input);
return 0;
}
実装のポイント
-
fgets
を使用して入力を一度に受け取る:-
fgets
を使って一度に複数の文字を読み取ります。fgets
の引数で指定したバッファのサイズに応じて読み取りますが、もしバッファが足りない場合は、再度realloc
を使ってバッファを拡張します。
-
-
realloc
による動的メモリ拡張:-
fgets
の呼び出し後、文字列の長さ(strlen
)をチェックし、改行文字が含まれていなければ、バッファサイズを倍増します。その後、再度fgets
を使って、残りの入力を読み取るためにメモリを拡張します。
-
-
改行文字の処理:
-
fgets
は入力中の改行文字も読み込むため、改行文字を検出して、その場合に入力を終了する処理を加えています。
-
動的メモリ範囲の拡張の理解
fgets
や scanf
のような方法でも、入力が増えるたびに realloc
でメモリを拡張することができます。重要なのは、バッファのサイズが足りなくなった時に、その都度メモリを再確保して範囲を広げていくことです。これにより、固定サイズのバッファを超えた入力を効率的に処理できます。
-
fgets
を使う: 一度に複数の文字を入力でき、入力が終わったら改行を取り除く処理を加えます。 -
scanf
を使う:scanf
で入力のフォーマットを指定して処理しますが、fgets
よりも柔軟性に欠けるため、複雑な入力には不向きです。
結論
-
getchar
を使わずとも、fgets
やscanf
を使って動的にメモリを拡張することができます。重要なのは、入力を逐次的に受け取る(または一度に受け取る)ときに、メモリが不足した場合にrealloc
を使って拡張することです。 - メモリの拡張が必要な場合、
fgets
のような関数で入力を一度に読み取ってから処理する方法が便利で、効率的です。