#if 0
お題:以下の問題提起に対してリーダビリティを優先したコードを示せ、コードの実際の内容は適宜定めよ
.....
nul ターミネートな文字列のお尻に、追加してべたべたといろいろ引っつけることを想定してほしい
実際の末尾追加処理は下請け関数に全部おまかせし、
親側では char * を渡して char * を結果として受け取る、
あと下請け関数側から成功・失敗フラグも受け取る
親側では複数の
realloc() の間で変わっていく
char * をいちいち把握したくない、
成功時の結果と失敗の報告だけほしい
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct String String;
/**
* String
* 可変長文字列コンテナ。
* getter/setter は省略。
*/
struct String {
size_t size; /* 確保した buffer のサイズ。1以上、length+1以下 を維持。 */
size_t length; /* 使用中の buffer の長さ。0以上、size-1以下 を維持。 */
char *buffer; /* 文字列バッファー。buffer[ length ] には '\0' を維持。 */
};
/**
* src からコンテナを構築。
* メモリ確保に失敗したら NULL を返し、成功したら String* を返す。
*/
static String *StringAllocate( const char *src )
{
size_t srclen
= strlen( src
);
String
*string
= ( String
* )malloc( sizeof( String
) ); if( !string ){
return NULL;
}
string->size = srclen + 1;
string->length = srclen;
string
->buffer
= ( char* )malloc( sizeof( char ) * string
->size
); if( !string->buffer ){
return NULL;
}
memmove( string
->buffer
, src
, srclen
); return string;
}
/**
* コンテナの破棄。string が無効だった場合の動作は未定義。
*/
static void StringFree( String *string )
{
if( string ){
}
}
/**
* コンテナの buffer を伸縮。resize が 0 以下だったらサイズを 1 にする。
* 伸縮に失敗したら NULL を返す。この時、buffer を開放しない。
* 成功したら String* を返す。
*/
static String *StringResize( String *string, size_t resize )
{
if( resize <= 0 ){
resize = 1;
}
char *tmp
= ( char* )realloc( string
->buffer
, resize
); if( !tmp ){
return NULL;
}
string->buffer = tmp;
string->size = resize;
if( resize < string->length ){
string->length = resize - 1;
string->buffer[ string->length ] = '\0';
}
return string;
}
/**
* コンテナの buffer の末尾に pushc を追加する。
* size が足りない場合は自動で伸縮し、伸縮に失敗したら NULL を返す。この時、buffer を開放しない。
* 成功したら String* を返す。
*/
static String *StringPushBack( String *string, char pushc )
{
if( string->length >= string->size - 1 ){
if( !StringResize( string, string->size * 2 ) ){
return NULL;
}
}
string->buffer[ string->length++ ] = pushc;
string->buffer[ string->length ] = '\0';
return string;
}
static inline void DumpString( const char* head, const String* string )
{
// printf( "%s: size %4d: length %4d: '%s'\n", head, string->size, string->length, string->buffer );
printf( "%s: '%s'\n", head
, string
->buffer
); }
int main( void )
{
int i = 0;
size_t nalphas = 26;
String *string = NULL;
string = StringAllocate( "test:test:test" );
if( !string ){
}
/* Resize Test */
DumpString( "resize before", string );
if( !StringResize( string, 20 ) )
goto ERROR;
DumpString( "resize after", string );
if( !StringResize( string, 6 ) )
goto ERROR;
DumpString( "resize after", string );
if( !StringResize( string, 0 ) )
goto ERROR;
DumpString( "resize after", string );
/* PushBack Test */
for( i = 0; i < nalphas; ++i ){
if( !StringPushBack( string, 'a'+i ) ){
goto ERROR;
}
DumpString( "string", string );
}
StringFree( string );
ERROR:
StringFree( string );
}