2010-02-28 9 views
5

meine Funktion:in C: Warum existiert eine Stack zugewiesene Struktur außerhalb der Funktion?

struct hostent * gethost(char * hostname){ 
    if(/*some condition under which I want 
     to change the mode of my program to not take a host*/){ 
     return null 
    } 
    else{ 
     struct hostent * host = gethostbyname(hostname); 
     return host; 
    } 
} 

in Haupt:

struct hostent * host = gethost(argv[2]); 

(keine kleinere Fehler im Code ignorieren, ich bin aus dem Gedächtnis spucken)

das funktioniert gut. und Valgrind sagt mir nicht, dass ich die Erinnerung verliere, obwohl ich nicht frei bin.

Warum? Ich dachte, dass Sachen, die auf dem Stapel zugewiesen sind, verschwinden, wenn der Funktionsaufruf zurückkehrt? oder ist es, weil ich den Zeiger zurückgebe? Ist das in irgendeiner Weise gefährlich?

Antwort

10

host ist nicht auf dem Stapel zugeordnet, nur ein Zeiger darauf ist auf dem Stapel. Der Zeiger wird kopiert, wenn die Funktion zurückkehrt, also ist nichts falsch mit dem Code.

Beachten Sie, dass gethostbyname Speicher tatsächlich nicht dynamisch alloziert. Es gibt immer einen Zeiger auf denselben statisch zugewiesenen Speicherblock zurück, weshalb valgrind kein Leck meldet. Seien Sie jedoch vorsichtig, denn das bedeutet, dass Sie das hostent, das von Ihrer Funktion zurückgegeben wird, kopieren müssen, wenn Sie den Wert für später speichern möchten, da weitere Aufrufe an gethost es überschreiben werden.

+0

Ah vielen Dank. Es ist also einzigartig für 'gethostbyname'? Wenn ich das zum Beispiel für ein 'char *' mache, werden die Werte in diesem Array möglicherweise später überschrieben? Mein Programm muss nur mit einem Host pro Lauf umgehen, also sollte das in Ordnung sein. –

+0

Ob der Wert, auf den ein Zeiger zeigt, bei späteren Aufrufen überschrieben wird, hängt von der Funktion ab, die Sie aufrufen. Für jede C-Standardbibliotheksfunktion, die einen Zeiger zurückgibt, den Sie nicht übergeben, können Sie davon ausgehen, dass sie einen Zeiger auf den statischen Speicher zurückgibt und überschrieben werden kann. – Gabe

0

Nun, der Speicher ist nicht durchgesickert, bis alle Verweise darauf verloren sind, in Ihrem Beispiel wird der Zeiger zurückgegeben, so dass es immer noch einen Verweis darauf gibt.

Allerdings ist es eine schlechte Design-Entscheidung in den meisten Fällen, sich auf einen anderen Teil des Codes zu verlassen, um dynamischen Speicher freizugeben. Wenn die Funktion beispielsweise eine Struktur zurückgeben muss, sollte der Aufrufer dies tun und einen Zeiger an die Struktur übergeben.

+2

Der Speicher ist nicht durchgesickert, weil 'gethostbyname' keine dynamische Zuweisung durchführt. Es gibt jedes Mal einen statischen Zeiger zurück. – Gabe

+2

Und wer, sagen Sie, verfolgt Verweise auf diesen Zeiger?:) – vladr

+2

Niemand verfolgt Verweise auf den Zeiger. Der Speicherblock wird zugewiesen, wenn die Socket-Bibliothek geladen wird und die Zuweisung nicht aufgehoben wird, bis der Prozess beendet oder die Socket-Bibliothek entladen wird. – Gabe

2

aus dem Handbuch:

RETURN VALUE 
     The gethostbyname() and gethostbyaddr() functions return the hostent 
     structure or a NULL pointer if an error occurs. On error, the h_errno 
     variable holds an error number. When non-NULL, the return value may 
     point at static data, ... 

Einige Speicher an der Kompilierzeit reserviert ist (dh innerhalb des binären Code.) Für die Struktur, die Funktion gibt einen Zeiger auf diesen Speicher.

3

Es ist in Ordnung und ist undicht, da der zurückgegebene Zeiger nicht auf Daten auf Stapel oder Heap zeigt, aber einige statische Variable.

http://linux.die.net/man/3/gethostbyname:

Die Funktionen gethostbyname() und gethostbyaddr() können Zeiger auf statische Daten zurückgeben, die später überschrieben werden können durch aufruft. Das Kopieren des struct hostent ist nicht ausreichend, da es Zeiger enthält; Eine tiefe Kopie ist erforderlich.

+0

Warum "global"? Global und statisch sind nicht dasselbe. – Ben