2015-09-04 2 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()' ed, которая обычно называется «утечкой памяти». – alk

+2

@alkk: ​​Да, плохая фразировка с моей стороны. УКАЗАТЕЛЬ мертв/ушел. –

ответ

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); 

Таким образом, буфер выделяется один раз и освобождается правильно.

В качестве альтернативы, можно использовать два указателя

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()' не равно -1 перед 'free (журнал) '? – chux

+0

@alk Правда, поэтому я и предложил альтернативу. Как ни странно, альтернативный неповторяющийся код длиннее, больше подвержен ошибкам и сложнее поддерживать корректно. – user3386109

0

Да. Вероятно, asprinf не попадет в одно и то же место памяти и не знает о предыдущих вызовах.

2

находится там [а] [...] утечку памяти

Определенно да.

Ссылка на память, выделенную на 1-ом вызове aprintf() получает перезаписаны 2 вызова aprintf(), так что нет никаких шансов на free() 1-й выделенной памяти больше, это «утечка».

Чтобы исправить это ввести 2-й (временный) указатель:

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); 
    } 

    asprintf(&log, format, name); 
} 

/* Use log. */ 

free(log); 

Добавление проверки ошибок в системные вызовы оставляется читателю в качестве упражнения.

3-й подход к этому только с использованием функций стандарта 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); 
Смежные вопросы