2011-12-03 7 views
1

すべての引数を連結されたchar配列として返す関数を作成しようとしています。残念ながら、関数の使用中に「無効なポインタ」エラーが発生します。私はC言語に新しいので、おそらく私はこのようにreallocを使うのが間違っています。forループのRealloc

char* concat(int argc, ...) { 
    char* result; 

    va_list args; 
    va_start(args, argc); 

    int i; 
    for (i = 0; i < argc; i++) { 
     char* s = va_arg(args, char*); 
     int length = (result) ? strlen(result) : 1; 

     char* tmp = (char*)realloc(result, sizeof(char) * (strlen(s) + length - 1)); 
     if (tmp == NULL) { 
      throw_error("Realloc failed in `concat`."); 
     } 

     result = tmp; 
     memcpy(&(result[length-1]), s, strlen(s)); 

     printf("result: %s\n", s); 
    } 

    va_end(args); 
    return result; 
} 

エラーメッセージ、それは助けることができる場合:

result = (char*)realloc(result, sizeof(char) * (strlen(s) + length - 1)); 

*** glibc detected *** ./pascc: realloc(): invalid pointer: 0x00000000006060c8 *** 
======= Backtrace: ========= 
/lib/x86_64-linux-gnu/libc.so.6(+0x76bb6)[0x7f9953be8bb6] 
/lib/x86_64-linux-gnu/libc.so.6(realloc+0x338)[0x7f9953beed58] 
./pascc[0x401368] 
./pascc[0x400f85] 
./pascc[0x4019bb] 
./pascc[0x403c49] 
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xff)[0x7f9953b90eff] 
./pascc[0x400e29] 
======= Memory map: ======== 
00400000-00406000 r-xp 00000000 08:05 2885504 

をメモリリークを避けるために、私はこのような何か自分自身をREALLOCべきではないと、他のスレッドで読みます

私はこれを行う良い方法を見つけようとしています。助けていただければ幸いです。

+0

gccのオプション '-Wall -O3'は、"結果はこの関数で初期化されずに使用されるかもしれません "と伝えます。そして、私はvalgrindもあなたに「条件付きの価値は初期化されていない価値に依存する」のようなものを教えてくれると確信しています。 –

答えて

7

初期化されていないポインタを指定しています。

char* result; 

あなたはNULLポインタまたはmallocによって割り当てられたメモリを指すポインタを使用する必要がありますreallocを使用します。

char* result = NULL; 
+0

いいえ、 'result'は初期化されていません。この行はおそらく最初に問題を引き起こしています: 'int length =(result)? strlen(結果):1; ' – Marlon

+0

+1。また、 '(strlen(s)+ length - 1)'は '(strlen(s)+ length + 1)'でなければなりません。 'strlen'は端末のヌルバイトを含みません。例えば、' strlen( "a") 'は' 1'なので、スペースを割り当てるのに '+ 1'が必要です。 – ruakh

+0

確かに、私はまだその部分をテストしていませんでした。 –

3

なぜ必要なサイズを決定してから、1つのmallocを実行しますか?このような

何か(警告が、私はこの答えを入力するよ、私は便利なCコンパイラを持っていない):

char* concat(int argumentCount, ...) 
{ 
    char* arguments[argumentcount]; // not sure this works in C. 
    int index; 
    char* result; 
    size_t totalSize = 1; 

    va_list argumentVector; 
    va_start(argumentVector, argumentCount); 

    for (index = 0; index < argumentCount; ++index) 
    { 
    arguments[index] = va_arg(argumentVector, char*); 

    totalSize += strlen(arguments[index]); 
    } 

    va_end(argumentVector); 

    result = calloc(totalSize, sizeof(char)); 

    for (index = 0; index < argumentCount; ++index) 
    { 
    strcat(result, arguments[index]); 
    } 
} 
+0

私は思った良いオプションです。私はどちらがより効率的であるかを調べるためにテストします。 –

1

@MarkByers右ですが、私はいくつかのより多くの変更を加えることと思います。私は:

  1. 変更char *result;からchar *result = NULL;に変更します。
  2. 変更int length = (result) ? strlen(result) : 1;int length = (result) ? strlen(result) : 0;
  3. 変更char* tmp = (char*)realloc(result, sizeof(char) * (strlen(s) + length - 1));~char* tmp = (char*)realloc(result, sizeof(char) * (strlen(s) + length + 1));
  4. 変更memcpy(&(result[length-1]), s, strlen(s));~strcpy(result + length, s);
  5. free(result);を追加してから、throw_errorを呼び出してから、関数を終了することを前提とします(C++では例外が発生する)。

理由:

  1. resultreallocコールは奇妙な何かをしないように、のようなランダムなメモリを拡張したりfreeしようとする初期化されていることを確認します。
  2. lengthは、常にの文字列をresultに格納します。
  3. オリジナルのlength文字をresultに、新しいstrlen(s)文字をsに、終了文字をNULLバイトに格納するのに十分な領域を割り当てます。
  4. strlen(s)を再度計算することなく、文字列をコピーします(終端のNULLバイトを含む)。既に格納されている文字列lengthをスキップするだけで済みます。
  5. reallocコールで問題が発生しても、すでに割り当てられているメモリがリークしないようにします。
+0

'strcpy(result + length、s)'の代わりに 'memcpy(result + length、s、strlen(s)+ 1)'があります。 –