2011-01-28 3 views
31
#include <stdio.h> 

int foo1(void) 
{ 
    int p; 
    p = 99; 
    return p; 
} 

char *foo2(void) 
{ 
    char buffer[] = "test_123"; 
    return buffer; 
} 

int *foo3(void) 
{ 
    int t[3] = {1,2,3}; 
    return t; 
} 

int main(void) 
{ 
    int *p; 
    char *s; 

    printf("foo1: %d\n", foo1()); 
    printf("foo2: %s\n", foo2()); 
    printf("foo3: %d, %d, %d\n", p[0], p[1], p[2]); 
    return 0; 
} 

Quando compilo questo con gcc -ansi -pedantic -W -Wall i problemi del compilatore di avviso messaggi per foo2() e foo3():restituendo una variabile locale da funzioni in C

warning: function returns address of local variable 

ho pensato che non è permesso di restituire un variabile locale, ma foo1() funziona bene e sembra che ci sia un'enorme differenza tra restituire il puntatore a un oggetto locale e l'oggetto stesso.

Qualcuno potrebbe far luce su questo problema? Grazie in anticipo!

risposta

21

Il problema qui è che quando si crea la variabile locale viene allocata nello stack e quindi non è disponibile una volta che la funzione termina l'esecuzione (l'implementazione varia qui). Il modo preferibile sarebbe utilizzare malloc() per riservare memoria non locale. il pericolo qui è che devi deallocare (free()) tutto ciò che hai assegnato usando malloc(), e se si dimentica, si crea una perdita di memoria.

+0

Un altro pericolo è che se non si reimposta (ad esempio 'memset') la memoria allocata, questa potrebbe perdere informazioni dalla pila. – jweyrich

5

Qualsiasi variabile ha un po 'di spazio nella memoria. Un puntatore fa riferimento a quello spazio. Lo spazio occupato dalle variabili locali viene deallocato quando ritorna la chiamata alla funzione, il che significa che può essere e verrà riutilizzato per altre cose. Di conseguenza, i riferimenti a quello spazio finiranno per indicare qualcosa di completamente non correlato. Le matrici in C sono implementate come puntatori, quindi questo si applica a loro. E gli array costanti dichiarati in una funzione valgono anche come locali.

Se si desidera utilizzare un array o un altro puntatore oltre l'ambito della funzione in cui è stato creato, è necessario utilizzare malloc per riservare lo spazio per esso. Lo spazio prenotato usando malloc non verrà riallocato o riutilizzato finché non verrà rilasciato esplicitamente chiamando gratuitamente.

+2

+1. In pratica ciò significa che è necessario allocare un valore di ritorno sull'heap piuttosto sullo stack. È necessario utilizzare malloc o similair sugli "array" che si desidera restituire. O meglio, prendi un puntatore su un buffer + una lunghezza del buffer come parametri. – stefan

+0

@stefan: Sì, è un buon punto. Ho aggiunto altri suggerimenti su come risolvere questo alla risposta. –

+1

'Le matrici in C sono implementate come puntatori' è un'eccessiva semplificazione; è accettabile dal punto di vista del contesto, ma esistono grosse differenze tra gli array e i puntatori (oltre a molte somiglianze). –

15

Per foo1(), si restituisce un copia della variabile locale, non la variabile locale stessa.

Per le altre funzioni, si restituisce una copia di un puntatore a una variabile locale. Tuttavia, tale variabile locale viene deallocata al termine della funzione, quindi si finisce con brutti problemi se si tenta di fare riferimento in seguito.

0

Sì, si sta restituendo un array, che in realtà è un puntatore dietro le quinte, all'indirizzo della posizione di memoria in cui è memorizzato il contenuto della variabile inizializzata. Quindi ti avverte che potrebbe non essere altrettanto utile restituire un risultato del genere, quando invece potresti davvero voler dire uno dei valori dell'array.