2011-01-28 12 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; 
} 

Kiedy skompilować to z gcc -ansi -pedantic -W -Wall problemów kompilatora komunikaty ostrzegawcze dla foo2() i foo3():powrocie zmiennej lokalnej z funkcji w C

warning: function returns address of local variable 

myślałem, że nie dopuszcza się zwróci zmienna lokalna, ale foo1() działa dobrze i wydaje się, że istnieje ogromna różnica między zwracaniem wskaźnika do lokalnego obiektu a samym obiektem.

Czy ktokolwiek mógłby rzucić nieco światła na tę kwestię? Z góry dziękuję!

Odpowiedz

21

Problem jest to, że podczas tworzenia zmiennej lokalnej jest przydzielona na stosie, a zatem jest niedostępne, gdy funkcja zakończy wykonanie (realizacja zależy tutaj). Preferowanym sposobem byłoby użycie malloc(), aby zarezerwować pamięć nielokalną. Niebezpieczeństwo polega na tym, że musisz zwolnić (free()) wszystko, co przydzieliłeś, używając malloc(), a jeśli zapomnisz, stworzysz przeciek pamięci.

+0

Innym niebezpieczeństwem jest, jeśli nie zresetujesz (np. 'Memset') przydzielonej pamięci, może to spowodować wyciek informacji ze stosu. – jweyrich

5

Każda zmienna ma trochę miejsca w pamięci. Wskaźnik odwołuje się do tej przestrzeni. Przestrzeń, którą zajmują zmienne lokalne, jest zwalniana, gdy funkcja zwraca, co oznacza, że ​​może i będzie ponownie używana do innych celów. W związku z tym odniesienia do tej przestrzeni zakończą się, wskazując na coś zupełnie niezwiązanego. Tablice w C są zaimplementowane jako wskaźniki, więc to odnosi się do nich. A stałe tablice zadeklarowane w funkcji również liczą się jako lokalne.

Jeśli chcesz używać tablicy lub inny wskaźnik poza zakres funkcji, w którym jest utworzony, trzeba używać malloc aby zarezerwować miejsca dla niego. Miejsce zarezerwowane przy użyciu malloc nie zostanie ponownie przydzielone ani ponownie użyte, dopóki nie zostanie jawnie zwolnione poprzez bezpłatne połączenie.

+2

+1. W praktyce oznacza to, że musisz przydzielić wartość zwracaną na stercie, a nie na stosie. Musisz użyć malloc lub similair na "tablicach", które chcesz zwrócić. Lub lepiej off, weź wskaźnik do bufora + długość bufora jako parametry. – stefan

+0

@stefan: Tak, to dobra uwaga. Dodałem więcej sugestii, jak rozwiązać ten problem. –

+1

"Tablice w C są zaimplementowane jako wskaźniki" to nadmierne uproszczenie; Granica ta jest akceptowalna dla kontekstu, ale istnieją znaczne różnice między tablicami a wskaźnikami (a także wieloma podobieństwami). –

15

Dla foo1() zwraca się kopię zmiennej lokalnej, a nie samą zmienną lokalną.

W przypadku innych funkcji zwraca się kopię wskaźnika do zmiennej lokalnej. Jednak lokalna zmienna jest deallocated po zakończeniu funkcji, więc kończy się nieprzyjemnych problemów, jeśli spróbujesz odwołać się później.

0

Tak wracasz tablicę, która jest w rzeczywistości wskaźnik za kulisami, na adres lokalizacji pamięci, w którym zawartość zmiennej już zainicjowanego są przechowywane. Ostrzega was, że może nie być tak przydatne, aby zwrócić taki wynik, kiedy naprawdę może oznaczać jedną z wartości tablicy.

Powiązane problemy