動的文字列ビルダー
CoddyのCジャーニー「Object Oriented Programming」セクションの一部 — レッスン 59/61。
チャレンジ
簡単テキストを追加するたびに自動的に拡張される動的な文字列コンテナ、StringBuilder を作成しましょう。これは、このコースで習得した OOP パターンと動的メモリ管理を組み合わせた実用的なユーティリティです。
コードは 3 つのファイルに分けて構成します:
stringbuilder.h: 3 つのメンバ(char*のバッファ、現在の長さを表すsize_t、合計容量を表すsize_t)を持つStringBuilder構造体を宣言します。StringBuilder の作成、テキストの追加、最終的な文字列の取得、およびメモリの解放を行うための関数プロトタイプを宣言します。インクルードガードは必須です。stringbuilder.c: StringBuilder システムを実装します:create_stringbuilder— ヒープ上に StringBuilder を割り当て、初期容量 16 バイトでバッファを初期化し、長さを 0 に設定し、バッファが空の文字列(null 終端)として始まるようにします。append— StringBuilder のポインタと追加する文字列を受け取ります。新しく必要となる長さを計算します。容量を超える場合は、容量を 2 倍にし(必要に応じて繰り返し)、reallocを使用してバッファを拡張します。その後、strcatを使用して新しいテキストを連結します。get_string— 内部バッファへのポインタを返します(読み取り専用アクセス)。free_stringbuilder— 最初にバッファを解放し、次に StringBuilder 構造体自体を解放します。
main.c: 追加する文字列の数を示す整数を読み取ります。次に、fgetsを使用して各文字列を読み取り、StringBuilder に追加します。すべての文字列が追加されたら、get_stringを使用して組み立てられた完全な文字列を出力します。最後に、StringBuilder を解放します。
このチャレンジで使用する 2 つの重要な関数:
realloc(ptr, new_size)— 以前に割り当てられたメモリブロックのサイズを変更します。既存のブロックへのポインタと、バイト単位の新しい希望サイズを受け取り、サイズが変更された(移動された可能性のある)ブロックへのポインタを返します。バッファを拡張する必要があるときにappend内で使用します:sb->buffer = (char*)realloc(sb->buffer, sb->capacity);fgets(buffer, size, stream)— 入力ストリームからテキストの 1 行を文字配列に読み込み、改行文字に達するか、size - 1文字が読み込まれた時点で停止します。バッファ内に改行文字が残るため、手動で取り除く必要があります。main.cで各入力文字列を読み取るために使用します:fgets(line, sizeof(line), stdin);
末尾の改行を取り除くには:最後の文字が'\n'であるか確認し、それを'\0'に置き換えます。
プログラムは以下を受け取ります:
- 追加する文字列の数
- 各行に 1 つずつの文字列
入力が 3、次に Hello、 、 World の場合の出力例:
Hello World入力が 4、次に C、 is、 a、 great language! の場合の出力例:
C is a great language!入力が 1、次に SingleString の場合の出力例:
SingleString各追加操作の後に length フィールドを更新することを忘れないでください。再割り当てが必要かどうかを確認するときは、null 終端文字を考慮してください。バッファには length + new_text_length + 1 バイトのスペースが必要です。文字列の長さを測定するには <string.h> の strlen を使用してください。また、main.c で fgets を使用して文字列を読み取る前に、scanf の後に残った改行を消費するために getchar() を呼び出してください。
自分で試してみよう
#include <stdio.h>
#include <stdlib.h>
#include "stringbuilder.h"
int main() {
int n;
scanf("%d", &n);
getchar(); // 数値の後の改行を読み飛ばす
// TODO: create_stringbuilder() を使用して StringBuilder を作成する
// TODO: n 個の文字列を読み込み、それぞれを StringBuilder に追加する
// ヒント: 各行を読み込むには fgets などを使用する
// fgets を使用する場合は、改行文字の扱いに注意すること
// TODO: get_string() を使用して、組み立てられた完全な文字列を出力する
// TODO: free_stringbuilder() を使用して StringBuilder を解放する
return 0;
}