2011-12-15 8 views
5

Rozważmy następujący kod:C - zwraca wskaźnik char bez malloc

char* pointerTesting(void) { 

    char* test = "hello"; 
    return test; 
} 

int main() { 

    char* string = pointerTesting(); 
    printf("string: %s\n", string); 
} 

to nie ma problemu kompilacji i uruchamiania. Jednak w moim rozumieniu nie powinno to działać, ponieważ pamięć przydzielona do wskaźnika test znajduje się na stosie i jest zniszczona po powrocie do głównej.

Tak więc pytanie brzmi, w jaki sposób to działa bez malloc w funkcji pointerTesting()?

+3

Zobacz http://stackoverflow.com/questions/2589949/c-string-literals-where-do-they-go i kilka podobnych pytań na ten temat na stackoverflow. – jman

+0

* Wskaźnik * jest przydzielany na stosie (dla typowych implementacji), ale nie zwracasz wskaźnika, tylko kopia, jeśli ma wartość. Jest podobny do 'int n = 42; return n; '. Jest to alokacja tego, co wskazuje na to, co jest istotne. –

Odpowiedz

13

W tym przypadku ciąg "hello" jest przechowywany w pamięci globalnej *. Tak więc przydzielono już.

Dlatego jest nadal ważny po powrocie z funkcji.

Jednakże, jeśli to zrobił:

char test[] = "hello"; 
return test; 

Wtedy nie, to nie będzie działać. (niezdefiniowane zachowanie) W tym przypadku ciąg jest w rzeczywistości tablicą lokalną - która nie jest już aktywna po powrocie funkcji.

* Chociaż zazwyczaj tak jest, standard nie mówi, że musi być przechowywany w pamięci globalnej.
Ale ważną częścią jest to, że żywotność literału ciągu jest długością całego programu. (zobacz komentarze)

+0

Byłbym szczęśliwszy, gdyby twoja odpowiedź wspomniała, że ​​"witaj" jest w pamięci globalnej przez przypadek wdrożenia i _nie_ z powodu zakazanego zachowania w jakimkolwiek standardzie. – sarnold

+0

@sarnold Uzgodnione, czy powinienem zmienić to na "* zwykle * przechowywane w pamięci globalnej"? Czy powinienem powiedzieć "jest przechowywany * w innym miejscu *"? – Mysticial

+0

Podoba mi się gwiazdka, którą masz teraz. :) Dzięki! – sarnold

5

Wracasz wartość z test, którym jest adres pierwszego znaku w ciągu dosłowne "hello" (który, jak wszystkie napisowych, jest przechowywany w postaci tablicy char w taki sposób, że jest ona dostępna przez cały okres trwania programu). Jeśli próbujesz zwrócić adres adres z test do późniejszego wykorzystania, to tak, będziesz mieć problemy.

Teraz następujący fragment będzie nie praca:

char *pointerTesting(void) 
{ 
    char test[] = "hello"; 
    return test; 
} 

W tym przypadku, starasz się zwrócić adres pierwszego elementu tablicy obiektu, który jest lokalnym do funkcji, które będą nieważne po wyjściu funkcji. Pamiętaj, że w większości kontekstów wyrażenie typu "N-elementowa tablica T" zostanie zastąpione wyrażeniem typu "wskaźnik do T", którego wartością jest adres pierwszego elementu w tablicy.