2009-08-03 15 views
9

Diciamo che hanno la seguente funzione:Tornando un puntatore a una variabile automatica

char *getp() 
{ 
    char s[] = "hello"; 
    return s; 
} 

Poiché la funzione restituisce un puntatore a una variabile locale nella funzione da utilizzare all'esterno, intende causare una perdita di memoria?

P.S. Sto ancora imparando C quindi la mia domanda può essere un po 'ingenuo ...

[Update]
Quindi, se dire si desidera restituire un nuovo char[] array (cioè forse per una funzione stringa), cosa torni esattamente? Dovrebbe essere puntatore a una variabile esterna? cioè un char[] che non è locale alla funzione?

risposta

24

Non causerà una perdita di memoria. Farà un riferimento ciondolante. La variabile locale viene allocata nello stack e verrà liberata non appena viene portata fuori dall'ambito. Di conseguenza, quando la funzione termina, il puntatore che stai restituendo non punta più a una memoria che possiedi. Questa non è una perdita di memoria (la perdita di memoria è quando si assegna un po 'di memoria e non la si libera).

[Aggiornamento]: Per essere in grado di restituire un array allocato in una funzione, è necessario allocare lo stack di fuori (ad esempio nel mucchio) come:

char *test() { 
    char* arr = malloc(100); 
    arr[0] = 'M'; 
    return arr; 
} 

Ora, se si don' t free la memoria nella funzione di chiamata dopo aver finito di usarlo, si avrà una perdita di memoria.

+0

Assegna 'arr [0] = 'M';' necessario o era solo per dimostrare un'operazione non banale su 'arr'? – user1717828

+0

@ user1717828 quest'ultimo. –

13

No, non perde, dal momento che è stato distrutto dopo che getp() termina;

Il risultato sarà un comportamento indefinito, perché ora si ha un puntatore a un'area di memoria che non contiene più ciò che si pensa di fare e che può essere riutilizzato da chiunque.

Una perdita di memoria si verifica se l'array è stato memorizzato nell'heap senza eseguire una chiamata a free().

char* getp(){ 

    char* p = malloc(N); 
    //do stuff to p 
    return p; 
} 

int main(){ 
    char* p = getp(); 
    //free(p) No leak if this line is uncommented 
    return 0; 
} 

Qui, p non viene distrutto perché non è nello stack, ma nell'heap. Tuttavia, una volta terminato il programma, la memoria allocata non è stata rilasciata, causando una perdita di memoria (anche se è stata eseguita una volta che il processo è morto).

[UPDATE]

Se si desidera restituire una nuova c-string da una funzione, avete due opzioni.

  • Conservarlo nel mucchio (come l'esempio sopra o come this real example che restituisce una stringa duplicato);
  • passare un parametro di buffer

ad esempio:

//doesnt exactly answer your update question, but probably a better idea. 
    size_t foo (const char* str, size_t strleng, char* newstr); 

Qui, si avrebbe dovuto allocare memoria da qualche parte per newstr (potrebbe essere impilate o mucchio) prima di chiamare la funzione foo. In questo caso particolare, restituirebbe la quantità di caratteri in newstr.

8

Non si tratta di una perdita di memoria perché la memoria viene rilasciata correttamente.

Ma è un bug. Hai un puntatore alla memoria non allocato. Si chiama dangling reference ed è una fonte comune di errori in C. I risultati non sono definiti. Non vedrai alcun problema fino al momento dell'esecuzione quando tenti di usare quel puntatore.

0

s è una variabile di stack - è automaticamente de-referenziata alla fine della funzione. Tuttavia, il puntatore non sarà valido e farà riferimento a un'area della memoria che potrebbe essere sovrascritta in qualsiasi punto.

+0

Non è de-referenziato, ma non è più allocato nello stack. –

2

Non causerà perdita di memoria, ma causerà un comportamento indefinito. Questo caso è particolarmente pericoloso perché il puntatore punterà da qualche parte nello stack del programma e, se lo utilizzi, accederai a dati casuali. Tale puntatore, una volta scritto, può anche essere usato per compromettere la sicurezza del programma e farlo eseguire codice arbitrario.

3

Le variabili automatiche vengono distrutte alla fine della chiamata di funzione; non puoi restituire loro un puntatore. Quello che stai facendo potrebbe essere descritto come "restituire un puntatore al blocco di memoria che usava tenere s, ma ora non è utilizzato (ma potrebbe ancora avere qualcosa in esso, almeno per ora) e che sarà riempito rapidamente con qualcosa altrimenti interamente. "

+0

+1 per non usare la parola "stack". – sigjuice

1

Ho eliminato la mia risposta precedente dopo aver inserito il codice in un debugger e aver osservato lo smontaggio e la finestra di memoria.

Il codice nella domanda non è valido e restituisce un riferimento alla memoria di stack, che verrà sovrascritta.

Questa versione leggermente diversa, però, restituisce un riferimento a memoria fissa, e funziona bene:

char *getp() 
{ 
    char* s = "hello"; 
    return s; 
} 
+0

char s * ??? È permesso in C ??? – Alphaneo

+1

typo .... lo sai che intendevo char * s – abelenky

2

Nessun altro ha ancora detto un altro modo che si può fare questo costrutto valido: dire al compilatore che vuoi che l'array "s" abbia "durata di archiviazione statica" (questo significa che vive per la vita del programma, come una variabile globale). A tale scopo, la parola "statica":

char *getp() 
{ 
    static char s[] = "hello"; 
    return s; 
} 

Ora, il rovescio della medaglia è che ora c'è solo uno istanza di s, condivisa tra ogni chiamata della funzione getp(). Con la funzione come hai scritto, non importa. Nei casi più complicati, potrebbe non fare quello che vuoi.

PS: il solito tipo di variabili locali ha la cosiddetta "durata di archiviazione automatica", il che significa che una nuova istanza della variabile viene creata quando viene chiamata la funzione e scompare quando la funzione restituisce. Esiste una corrispondente parola chiave "auto", ma è comunque implicita se non si utilizza "statico", quindi non si vede quasi mai nel codice del mondo reale.

+0

I riferimenti 'static' sono memorizzati nell'Heap? –

+1

No, vengono caricati/creati all'avvio del programma, quindi la memoria per essi viene solitamente allocata in modo simile alla memoria che contiene il testo del programma stesso. – caf

Problemi correlati