2015-09-04 18 views
8

Ho un codice come questo: ho assegnato il registro due volte, c'è una potenziale perdita di memoria per il primo log &?asprintf(): come liberare i puntatori?

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

sì, stai perdendo memoria. la stringa con cui il primo asprintf ha creato e salvato un puntatore nel log ora viene cancellata/eliminata –

+2

@MarcB: "* la stringa che il primo' asprintf 'ha creato [...] ora cancellato/passato * "Non è corretto, come "stringa", cioè la memoria che è stata allocata, ancora * è * allocata. Tuttavia il riferimento ad esso (come 1 ° memorizzato in 'log') è andato. Quindi la memoria non può essere più 'libera()' ed, che comunemente si chiama "perdita di memoria". – alk

+2

@alkk: ​​sì, brutto fraseggio da parte mia. il POINTER è morto/andato. –

risposta

6

Sì, il codice perde, dal asprintf né i controlli, né i tentativi di riutilizzo, il puntatore precedente. Quindi, la memoria è semplicemente persa. Il modo migliore per evitare il problema nel tuo esempio sarebbe quello di riscrivere il codice come

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

free (log); 

In questo modo, il buffer si alloca una volta liberata correttamente.

In alternativa, è possibile utilizzare due puntatori

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

Il primo approccio ignora completamente il principio DRY: https://en.wikipedia.org/wiki/Don't_repeat_yourself – alk

+0

Quanto è importante verificare che il valore restituito di 'asprintf()' non sia -1 prima di 'free (log) '? – chux

+0

@alk True, ecco perché ho fornito l'alternativa. Ironia della sorte, il codice alternativo non ripetitivo è più lungo, più soggetto a errori e più difficile da mantenere correttamente. – user3386109

0

Sì. Probabilmente asprinf non colpirà la stessa posizione di memoria e non è a conoscenza delle chiamate precedenti.

2

c'è [a] [...] perdita di memoria

Sicuramente sì.

Il riferimento alla memoria allocata dal 1 ° chiamata a aprintf() viene sovrascritta dalla seconda chiamata a aprintf(), quindi non c'è alcuna possibilità di free() 1 ° memoria allocata più, si "fughe di notizie".

Per risolvere questo problema introdurre un secondo (temporanea) puntatore:

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

Un diverso e probabilmente più economico (più veloce come alcuni roba è gestire durante il tempo di compilazione, ma run-time) approccio a questo problema sarebbe il seguente:

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

L'aggiunta del controllo degli errori sulle chiamate di sistema viene lasciata al lettore come esercizio.

Un terzo approccio a questo solo utilizzando le funzioni standard 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); 

Un diverso e probabilmente più economico (più veloce come alcuni roba è gestire durante il tempo di compilazione, ma run-time) approccio a questo problema sarebbe il seguente:

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