【C言語】可変長文字列型を作成する

他言語でいうString型の様な、メモリサイズ(配列長)を気にせずに使える可変長文字列型をC言語で自作するサンプルです。
まぁ、普通でしたらC++使えば良いのですが。そこをC言語でやってみようという、あまり需要は無いかも知れないですね。

C言語ライブラリ「cmn-clib」に同じものがありますので、作るのがめんどくさい人はこちらからコピーでも。「CmnStringBuffer_xxx」という名前の関数がそれです。

使い方イメージ

可変長文字列型の名前は「CmnStringBuffer」としています。

Createでバッファを作成し、Setで文字列の設定、Appendで追加をします。使い終わったらFreeでメモリ開放です。

/* 可変長文字列の生成 */
CmnStringBuffer *buf = CmnStringBuffer_Create("hello");
printf(buf->string);   /* hello */

/* データをセット(上書き) */
CmnStringBuffer_Set(buf, "HELLO!");
printf(buf->string);   /* HELLO! */

/* データを追加 */
CmnStringBuffer_Append(buf, "123");
printf(buf->string);   /* HELLO!123 */
printf("文字列長:%d", buf->length);  /* 文字列長:9 */

/* 可変長文字列の破棄 */
CmnStringBuffer_Free(buf);

CmnStringBufferの実装

このプログラムは以下のページで作成したCmnDataBufferを拡張したものですので、こちらも合わせてご覧ください。

データ構造

可変長文字列型を構造体として定義します。

typedef struct _tag_CmnStringBuffer {
	CmnDataBuffer *_buf;	/**< 自動領域拡張バッファへのポインタ。内部的な処理で使う。 */
	char *string;			/**< 文字列へのポインタ。Append/Setによる領域拡張時にアドレスが変わる可能性があるため、利用側で保存せず、常に最新のポインタを参照すること。 */
	size_t length;			/**< 文字数 */
} CmnStringBuffer;

関数

CmnStringBuffer_Create : 文字列バッファ作成

引数strの文字列を初期値として、バッファを新規作成します。

/**
 * @brief 文字列バッファ作成
 *
 *  自動領域拡張をする文字列バッファを新規に作成する。
 *
 * @param str 文字列バッファに格納する文字列。NULLを指定した場合は空文字列を設定する。
 * @return 作成したバッファへのポインタ。作成に失敗した場合はNULLを返す。
 */
CmnStringBuffer* CmnStringBuffer_Create(const char *str)
{
	size_t strLen = 0;
	CmnStringBuffer *ret;

	ret = malloc(sizeof(CmnStringBuffer));
	if (ret == NULL) {
		return NULL;
	}

	if (str == NULL) {
		str = "";
	}
	strLen = strlen(str);

	ret->_buf = CmnDataBuffer_Create(strLen + 1);
	if (ret->_buf == NULL) {
		return NULL;
	}
	CmnDataBuffer_Set(ret->_buf, str, strLen + 1);
	ret->string = ret->_buf->data;
	ret->length = strLen;

	return ret;
}

CmnStringBuffer_Set : 文字列設定(上書き)

文字列を上書き設定します。元々設定されていた文字列は破棄され、引数strの内容で上書きされます。内部的には CmnDataBuffer を使っており、バッファ領域の拡張は CmnDataBuffer が行っています。

/**
 * @brief 文字列バッファへのデータ設定 *
 *  文字列バッファにデータを設定する。もとのデータは上書かれる。
 *
 * @param buf 文字列バッファ
 * @param str 設定する文字列
 * @return 正常:0, エラー:-1
 */
int CmnStringBuffer_Set(CmnStringBuffer *buf, const char *str)
{
	size_t strLen;
	strLen = strlen(str);

	/* 文字列を設定 */
	if (CmnDataBuffer_Set(buf->_buf, str, strLen + 1) != 0) {
		return -1;
	}

	buf->string = buf->_buf->data;
	buf->length = strLen;

	return 0;
}

CmnStringBuffer_Append : 文字列追加

現在設定されている文字列の末尾に、引数strの文字列を追加します。内部的には CmnDataBuffer を使っており、バッファの拡張は CmnDataBuffer が行っています。

/**
 * @brief 文字列バッファへのデータ追加
 *
 *  文字列バッファの末尾にデータを追加する。
 *
 * @param buf 文字列バッファ
 * @param str 追加する文字列
 * @return 正常:0, エラー:-1
 */
int CmnStringBuffer_Append(CmnStringBuffer *buf, const char *str)
{
	size_t strLen;
	strLen = strlen(str);

	/* '\0'を削除 */
	CmnDataBuffer_Delete(buf->_buf, 1);
	/* 文字列を追加 */
	if (CmnDataBuffer_Append(buf->_buf, str, strLen + 1) != 0) {
		return -1;
	}

	buf->string = buf->_buf->data;
	buf->length += strLen;

	return 0;
}

CmnStringBuffer_Free : 文字列バッファ破棄

文字列バッファを破棄してメモリを解放します。

/**
 * @brief 文字列バッファの解放
 *
 *  文字列バッファが不要になった場合、メモリ解放のために必ず本関数を呼び出すこと。
 *
 * @param buf 文字列バッファ
 */
void CmnStringBuffer_Free(CmnStringBuffer *buf)
{
	free(buf->_buf);
	free(buf);
}

コメント

タイトルとURLをコピーしました