2016-03-19 8 views
1

Es ist ziemlich schwer zu Wort meiner Frage so werde ich nur ein Code Beispiel:C-String Umfang zwischen Funktionen

#include <stdio.h> 

typedef struct { 
    char *str; 
} strHold; 

void f2(char *s) 
{ 
    *s = "Char 2"; 
} 

void f3(strHold *str) 
{ 
    (*str).str = "Struct 2"; 
} 

int main() 
{ 
    char *s1 = "Char 1"; 
    strHold str1; 
    str1.str = "Struct 1"; 

    //f2(s1); 
    f3(&str1); 

    printf("%s, ", s1); 
    printf("%s", str1.str); 

    return 0; 
} 

dieses C-Programm läuft, und zeigt sogar „Struct 2“ auf dem zweiten Druck. Funktion f2 funktioniert jedoch nicht, wie in, wenn ich den Kommentar entfernen, stürzt das Programm ab. Ich bin eigentlich nicht überrascht, dass f2 nicht funktioniert, ich frage mich, warum funktioniert f3?

Wenn ich eine String-Konstante innerhalb eines Bereichs der Funktion definieren, sollten diese Daten freigegeben werden, sobald ich den Bereich der Funktion verlassen, oder? Was bedeutet, dass Daten in Müll umgewandelt würden, sobald ich in den aufrufenden Funktionsumfang zurückkomme.

Also ... wie funktioniert die Strukturversion? Kann jemand erklären, wie Speicher in diesen beiden Situationen funktioniert, und was ist der "richtige" Weg, Strings unbekannter Länge in einer aufrufenden Funktion von einer aufgerufenen Funktion zu initialisieren?

+0

Sie bekommen viele Warnungen aus diesem Programm sein sollten, wenn sie bauen, lesen, versuchen zu verstehen, was sie bedeuten, und zu beheben, die Ursache der Warnungen (und durch „reparieren "Ich werfe die Warnungen nicht einfach weg." –

+0

Erfahren Sie außerdem, wie Sie * by Referenz in c * emulieren. –

Antwort

1

Sie Compiler sollte eine Warnung für diese Linie gegeben haben:

*s = "Char 2"; 

Hier *s ist ein char und Sie versuchen, eine Zeichenfolge (char*), um es zuzuweisen. Fix it, indem die Adresse s1 an die Funktion:

f2(&s1); 

und ändern Sie die Funktion Header:

void f2(char **s) 

When I define a string constant inside a function's scope, that data should be freed once I exit the scope of the function, right? Which means that data would turn into garbage once I return into the calling function scope.

Nr Stringliterale haben statische Lebensdauer, was bedeutet, dass sie existieren so lange wie das Programm tut. Nur lokale Variablen innerhalb der Funktion werden zerstört, sobald die Funktion endet.

+0

Dies war die nützlichste Antwort. Ich habe meinen Fehler gerade früher mit f2 bemerkt und in & s1 im Call und ** s im Header behoben, aber die Art, wie String-Literale gespeichert werden, war meine eigentliche Frage, und Sie haben das beantwortet, jetzt weiß ich, was ich mache. Vielen Dank. – Aqo

1

In:

void f2(char *s) 
{ 
    *s = "Char 2"; 
} 

erhalten Sie einen Compiler-Fehler: Sie sind dereferenzieren der Zeiger, die wollen ergibt einen Charakter (Typ) und jetzt eine Zeichenfolge dem Charakter zuzuordnen.

Allgemeiner ausgedrückt, ein String-Literal muss irgendwo im Speicher gespeichert werden, andernfalls kann das Programm seinen Wert nicht zuweisen. Nach dem Verlassen der Funktion wird das Literal immer noch irgendwo im Speicher gespeichert.

1

Sie dürfen nicht versuchen, Zeichenfolgenliterale zu ändern, oder Sie rufen undefiniertes Verhalten auf.

"Char 1" ist zugewiesen, daher enthält das Argument s von f2 einen Zeiger auf ein Zeichenfolgenliteral. Wenn Sie also *s etwas zuweisen, bedeutet das, dass Sie versuchen, ein Zeichenfolgenliteral zu ändern.

Um die lokale Variable des Aufrufers zu ändern, verwenden Sie Zeiger auf die zu ändernde Variable.

Sie müssen nicht die Stringliterale frei, und Sie müssen nicht versuchen, sie zu befreien, weil sie mit statischer Speicherdauer zugeordnet sind, nach N1256 6.4.5 Stringliterale-5 und N1570 6.4.5 Stringliterale -6.

Die Strukturversion funktioniert, weil Sie den Zeiger an die Struktur übergeben und damit ein Mitglied der Struktur geändert haben, ohne zu versuchen, Zeichenfolgenliterale zu ändern.

Dieser Code wird funktionieren:

#include <stdio.h> 

typedef struct { 
    char *str; 
} strHold; 

void f2(char **s) /* add * to receive a pointer to char* */ 
{ 
    *s = "Char 2"; 
} 

void f3(strHold *str) 
{ 
    (*str).str = "Struct 2"; 
} 

int main(void) 
{ 
    char *s1 = "Char 1"; 
    strHold str1; 
    str1.str = "Struct 1"; 

    f2(&s1); /* add & to get the pointer to s1 */ 
    f3(&str1); 

    printf("%s, ", s1); 
    printf("%s", str1.str); 

    return 0; 
} 
0

Der Zeiger Sie verwendet haben, * s1 zu einem ausreichend großen Speicherblock zeigen sollte, für einen Anfänger eine Zeichenfolge lang genug, um Ihre längste Ausgabe enthalten. Erfahrenere Programmierer sollten malloc und kostenlos verwenden.

Für einen Anfänger:

static char buffer[80]; /* 80 chars of null bytes */ 
char  *s1;  /* pointer to string */ 
s1 = buffer;   /* pointer now pointing to beginning of buffer */ 
strcpy(s1,"Char 1") /* buffer now contains initial text, 
    rest is null bytes, so string is terminated correctly */