fork download
  1. #if 0
  2. お題:以下の問題提起に対してリーダビリティを優先したコードを示せ、コードの実際の内容は適宜定めよ
  3. .....
  4. nul ターミネートな文字列のお尻に、追加してべたべたといろいろ引っつけることを想定してほしい
  5. 実際の末尾追加処理は下請け関数に全部おまかせし、
  6. 親側では char * を渡して  char * を結果として受け取る、
  7. あと下請け関数側から成功・失敗フラグも受け取る
  8.  
  9. 下請け関数側は複数の realloc() を使っている、
  10. 親側では複数の realloc() の間で変わっていく char * をいちいち把握したくない、
  11. 成功時の結果と失敗の報告だけほしい
  12. 下請け関数がエラーを返してきたら、free() して exit().
  13. #endif
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17.  
  18. typedef struct String String;
  19.  
  20. /**
  21.  * String
  22.  * 可変長文字列コンテナ。
  23.  * getter/setter は省略。
  24. */
  25. struct String {
  26. size_t size; /* 確保した buffer のサイズ。1以上、length+1以下 を維持。 */
  27. size_t length; /* 使用中の buffer の長さ。0以上、size-1以下 を維持。 */
  28. char *buffer; /* 文字列バッファー。buffer[ length ] には '\0' を維持。 */
  29. };
  30.  
  31. /**
  32.  * src からコンテナを構築。
  33.  * メモリ確保に失敗したら NULL を返し、成功したら String* を返す。
  34. */
  35. static String *StringAllocate( const char *src )
  36. {
  37. size_t srclen = strlen( src );
  38.  
  39. String *string = ( String* )malloc( sizeof( String ) );
  40. if( !string ){
  41. return NULL;
  42. }
  43.  
  44. string->size = srclen + 1;
  45. string->length = srclen;
  46. string->buffer = ( char* )malloc( sizeof( char ) * string->size );
  47. if( !string->buffer ){
  48. free(string);
  49. return NULL;
  50. }
  51.  
  52. memmove( string->buffer, src, srclen );
  53. return string;
  54. }
  55.  
  56. /**
  57.  * コンテナの破棄。string が無効だった場合の動作は未定義。
  58. */
  59. static void StringFree( String *string )
  60. {
  61. if( string ){
  62. free( string->buffer );
  63. free( string );
  64. }
  65. }
  66.  
  67. /**
  68.  * コンテナの buffer を伸縮。resize が 0 以下だったらサイズを 1 にする。
  69.  * 伸縮に失敗したら NULL を返す。この時、buffer を開放しない。
  70.  * 成功したら String* を返す。
  71. */
  72. static String *StringResize( String *string, size_t resize )
  73. {
  74. if( resize <= 0 ){
  75. resize = 1;
  76. }
  77.  
  78. char *tmp = ( char* )realloc( string->buffer, resize );
  79. if( !tmp ){
  80. return NULL;
  81. }
  82.  
  83. string->buffer = tmp;
  84. string->size = resize;
  85. if( resize < string->length ){
  86. string->length = resize - 1;
  87. string->buffer[ string->length ] = '\0';
  88. }
  89.  
  90. return string;
  91. }
  92.  
  93. /**
  94.  * コンテナの buffer の末尾に pushc を追加する。
  95.  * size が足りない場合は自動で伸縮し、伸縮に失敗したら NULL を返す。この時、buffer を開放しない。
  96.  * 成功したら String* を返す。
  97. */
  98. static String *StringPushBack( String *string, char pushc )
  99. {
  100. if( string->length >= string->size - 1 ){
  101. if( !StringResize( string, string->size * 2 ) ){
  102. return NULL;
  103. }
  104. }
  105. string->buffer[ string->length++ ] = pushc;
  106. string->buffer[ string->length ] = '\0';
  107.  
  108. return string;
  109. }
  110.  
  111. static inline void DumpString( const char* head, const String* string )
  112. {
  113. // printf( "%s: size %4d: length %4d: '%s'\n", head, string->size, string->length, string->buffer );
  114. printf( "%s: '%s'\n", head, string->buffer );
  115. }
  116.  
  117. int main( void )
  118. {
  119. int i = 0;
  120. size_t nalphas = 26;
  121. String *string = NULL;
  122.  
  123. string = StringAllocate( "test:test:test" );
  124. if( !string ){
  125. perror( "StringAllocate" );
  126. exit( EXIT_FAILURE );
  127. }
  128.  
  129. /* Resize Test */
  130.  
  131. DumpString( "resize before", string );
  132.  
  133. if( !StringResize( string, 20 ) )
  134. goto ERROR;
  135. DumpString( "resize after", string );
  136.  
  137. if( !StringResize( string, 6 ) )
  138. goto ERROR;
  139. DumpString( "resize after", string );
  140.  
  141. if( !StringResize( string, 0 ) )
  142. goto ERROR;
  143. DumpString( "resize after", string );
  144.  
  145. /* PushBack Test */
  146.  
  147. for( i = 0; i < nalphas; ++i ){
  148. if( !StringPushBack( string, 'a'+i ) ){
  149. goto ERROR;
  150. }
  151. DumpString( "string", string );
  152. }
  153.  
  154. StringFree( string );
  155. exit( EXIT_SUCCESS );
  156. ERROR:
  157. StringFree( string );
  158. exit( EXIT_FAILURE );
  159. }
  160.  
Success #stdin #stdout 0s 2184KB
stdin
Standard input is empty
stdout
resize before: 'test:test:test'
resize after: 'test:test:test'
resize after: 'test:'
resize after: ''
string: 'a'
string: 'ab'
string: 'abc'
string: 'abcd'
string: 'abcde'
string: 'abcdef'
string: 'abcdefg'
string: 'abcdefgh'
string: 'abcdefghi'
string: 'abcdefghij'
string: 'abcdefghijk'
string: 'abcdefghijkl'
string: 'abcdefghijklm'
string: 'abcdefghijklmn'
string: 'abcdefghijklmno'
string: 'abcdefghijklmnop'
string: 'abcdefghijklmnopq'
string: 'abcdefghijklmnopqr'
string: 'abcdefghijklmnopqrs'
string: 'abcdefghijklmnopqrst'
string: 'abcdefghijklmnopqrstu'
string: 'abcdefghijklmnopqrstuv'
string: 'abcdefghijklmnopqrstuvw'
string: 'abcdefghijklmnopqrstuvwx'
string: 'abcdefghijklmnopqrstuvwxy'
string: 'abcdefghijklmnopqrstuvwxyz'