2015-09-04 16 views
8

私はこのようなコードを持っています:私はログを二度割り当てました、最初の&ログの潜在的なメモリリークはありますか?asprintf():ポインタを解放する方法は?

char *log = NULL; 
asprintf(&log, "Hello: %s", name); 
if (known_person== true){ 
    asprintf(&log, "%s, %s", log, ", my old friend."); 
} 
free (log); 
+0

はい、メモリがリークしています。最初のasprintfが作成してログへのポインタを保存した文字列が削除/消滅しました –

+2

@MarcB: "*最初の' asprintf'が作成した文字列[...]は今削除/消滅しました* "これは正しくない、 「文字列」として割り当てられたメモリであり、依然として*割り当てられています。しかし、( 'log'に格納されているように)それへの参照はなくなりました。だから、メモリを 'free()'にすることはできません。これは通常 "メモリリーク"と呼ばれます。 – alk

+2

@alkk:ええ、私のところに悪い句。 POINTERは死んだり消えたりしています。 –

答えて

6

はい、asprintfは前のポインタをチェックしたり、再利用しようとしたりしないため、コードがリークします。したがって、メモリは単に失われます。あなたの例では、問題を回避する最善の方法は、

char *log = NULL; 
if (known_person== true) 
    asprintf(&log, "Hello: %s, my old friend.", name); 
else 
    asprintf(&log, "Hello: %s", name); 

free (log); 

としてそのようにコードを書き換えることであろう、バッファは、一度割り当てられ、正しく解放されます。

また、次の2つのポインタ

char *temp = NULL; 
asprintf(&temp, "Hello: %s", name); 

char *log = NULL; 
if (known_person== true) { 
    asprintf(&log, "%s, my old friend.", temp); 
    free(temp); 
} 
else { 
    log = temp; 
} 

free (log); 
+0

第1のアプローチは、DRYの原則を完全に無視しています:https://en.wikipedia.org/wiki/Don't_repeat_yourself – alk

+0

'asprintf()'の戻り値が 'freeログ) '? – chux

+0

@alk真実なので、私は代わりを提供しました。皮肉なことに、代替の非反復コードは長くなり、エラーが発生しやすくなり、正しく維持するのが難しくなります。 – user3386109

0

はい。おそらくasprinfは、同じメモリの場所にヒットせず、以前の呼び出しに関する知識がありません。

2

を使用することができます[A]あり[...]メモリは、はい確かに

を漏らします。

aprintf()に第一の呼び出しによって割り当てられたメモリへの参照はaprintf()への第二の呼び出しによって上書きされますので、これ以上、それを「リーク」第一割り当てられたメモリfree()への可能性はありません。この問題への(いくつかのもののように速く、コンパイル時間の間に扱うが、実行時にされた)別の、おそらく安価なアプローチは次のようになり

char name[] = "C"; 
char * log = NULL; 

{ 
    char * log_tmp = NULL; 

    asprintf(&log_tmp, "Hello: %s", name); 
    if (known_person == true) 
    { 
    asprintf(&log, "%s, %s", log_tmp, ", my old friend."); 
    free(log_tmp); 
    } 
    else 
    { 
    log = log_tmp; 
    } 
} 

/* Use log. */ 

free(log); 

:第2(一時的な)ポインタを紹介し、この問題を解決するには

次のようになります。

#define FORMAT_STR "Hello: %s" 
#define FORMAT_SUFFIX_STR ", my old friend." 

... 

char name[] = "C"; 
char * log = NULL; 

{ 
    char format[sizeof FORMAT_STR""FORMAT_SUFFIX_STR + 1] = FORMAT_STR; 

    if (known_person == true) 
    { 
    strcat(format, FORMAT_SUFFIX_STR); 
    } 

    asprintf(&log, format, name); 
} 

/* Use log. */ 

free(log); 

システムコールのエラーチェックを追加することは、練習問題として残しています。

本のみ使用し、標準C関数への第三のアプローチは、次のとおりです。

char name[] = "C"; 
char * log = NULL; 

{ 
    char * log_tmp = NULL; 

    asprintf(&log_tmp, "Hello: %s", name); 
    if (known_person == true) 
    { 
    asprintf(&log, "%s, %s", log_tmp, ", my old friend."); 
    free(log_tmp); 
    } 
    else 
    { 
    log = log_tmp; 
    } 
} 

/* Use log. */ 

free(log); 

になり、この問題へのアプローチを(いくつかのものは、コンパイル時間の間に扱うが、実行時であると速い)異なると、おそらく安いです次のようになります。

#define FORMAT_STR "Hello: %s" 
#define FORMAT_SUFFIX_STR ", my old friend." 

... 

char name[] = "C"; 
char * log = NULL; 

{ 
    char format[sizeof FORMAT_STR""FORMAT_SUFFIX_STR + 1] = FORMAT_STR; 

    if (known_person == true) 
    { 
    strcat(format, FORMAT_SUFFIX_STR); 
    } 

    { 
    int s = snprintf(NULL, 0, format, name); 
    if (-1 == s) 
    { 
     /* failure */ 
    } 
    else 
    { 
     log = malloc(s + 1); 
     if (NULL == log) 
     { 
     /* failure */ 
     } 
     else 
     { 
     if (-1 == sprintf(log, format, name)) 
     { 
      /* failure */ 
     } 
     } 
    } 
    } 
} 

free(log); 
関連する問題