2010-06-28 9 views
37

Ich versuche zu verstehen, wie man dieses triviale Problem in C auf die sauberste/sicherste Weise löst. Hier ist mein Beispiel:Wie ordne ich einen neuen Stringwert korrekt zu?

#include <stdio.h> 

int main(int argc, char *argv[]) 
{ 
    typedef struct 
    { 
     char name[20]; 
     char surname[20]; 
     int unsigned age; 
    } person; 

    //Here i can pass strings as values...how does it works? 
    person p = {"John", "Doe",30}; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 
    // This works as expected... 
    p.age = 25; 
    //...but the same approach doesn't work with a string 
    p.name = "Jane"; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 

    return 1; 
} 

Die Fehler des Compilers ist:

main.c: In function ‘main’: main.c:18: error: incompatible types when assigning to type ‘char[20]’ from type ‘char *’

Ich verstehe, dass C (nicht C++) keine String-Typ hat und verwendet stattdessen Arrays von Zeichen, so eine andere Art und Weise, dies zu tun war, verändern das Beispiel struct Zeiger von Zeichen zu halten:

#include <stdio.h> 

int main(int argc, char *argv[]) 
{ 
    typedef struct 
    { 
     char *name; 
     char *surname; 
     int unsigned age; 
    } person; 

    person p = {"John", "Doe",30}; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 

    p.age = 25; 

    p.name = "Jane"; 

    printf("Name: %s; Age: %d\n",p.name,p.age); 

    return 1; 
} 

Dies funktioniert wie erwartet, aber ich frage mich, ob es einen besseren Weg, dies zu tun. Vielen Dank.

+0

Wenn wir struct in 'main()' deklarieren, kann nur eine Person darauf zugreifen. Versuchen Sie, aus dem Haupt herauszuziehen, um es als global zu verwenden – EsmaeelE

Antwort

29

Das erste Beispiel funktioniert nicht, weil Sie keine Werte zuweisen können - Arrays arbeiten (Art von) wie Const-Zeiger in dieser Hinsicht. Was Sie jedoch tun ist, einen neuen Wert in das Feld kopieren:

strcpy(p.name, "Jane"); 

Char-Arrays ist in Ordnung zu verwenden, wenn Sie die maximale Größe der Zeichenfolge im Voraus wissen, z.B. Im ersten Beispiel sind Sie 100% sicher, dass der Name in 19 Zeichen passt (nicht 20, weil immer ein Zeichen zum Speichern des abschließenden Nullwerts benötigt wird).

Umgekehrt sind Zeiger besser, wenn Sie die mögliche maximale Größe Ihrer Zeichenfolge nicht kennen und/oder Ihre Speichernutzung optimieren möchten, z. Vermeiden Sie die Reservierung von 512 Zeichen für den Namen "John". Bei Pointern müssen Sie jedoch den Puffer, auf den sie verweisen, dynamisch zuordnen und bei Bedarf freigeben, um Speicherlecks zu vermeiden.

Update: Beispiel für dynamisch zugewiesenen Puffer (die Struktur Definition in Ihrem zweiten Beispiel verwendet wird):

char* firstName = "Johnnie"; 
char* surname = "B. Goode"; 
person p; 

p.name = malloc(strlen(firstName) + 1); 
p.surname = malloc(strlen(surname) + 1); 

p.age = 25; 
strcpy(p.name, firstName); 
strcpy(p.surname, surname); 

printf("Name: %s; Age: %d\n",p.name,p.age); 

free(p.surname); 
free(p.name); 
7

Denken Sie an Saiten als abstrakte Objekte und char-Arrays als Container. Die Zeichenfolge kann eine beliebige Größe haben, der Container muss jedoch mindestens 1 mehr als die Zeichenfolge (um den Nullabschluss zu halten) sein.

C hat sehr wenig syntaktische Unterstützung für Strings. Es gibt keine String-Operatoren (nur char-array- und char-pointer-Operatoren). Sie können keine Zeichenfolgen zuweisen.

Aber Sie können Funktionen aufrufen, um zu erreichen, was Sie wollen.

Die Funktion strncpy() könnte hier verwendet werden. Für maximale Sicherheit empfiehlt folgende ich dieses Muster:

strncpy(p.name, "Jane", 19); 
p.name[19] = '\0'; //add null terminator just in case 

auch einen Blick auf die Funktionen strncat() und memcpy() haben.

+1

Für jetzt die beste Antwort, aber auch Péters ist gut (zeigt, wie man es mit Zeigern macht), also warte ich ein wenig mehr, um zu sehen, ob mehr Leute mehr Tipps hinzufügen können/Vorschläge zum Thema. –

4

Die beiden Strukturen sind unterschiedlich. Wenn Sie die erste Struktur initialisieren, werden etwa 40 Byte Speicher zugewiesen. Wenn Sie die zweite Struktur initialisieren, werden etwa 10 Byte Speicher reserviert. (Der tatsächliche Betrag ist architekturabhängig.)

Sie können String-Literale (Zeichenfolgenkonstanten) verwenden, um Zeichenarrays zu initialisieren. Aus diesem Grund

person p = {"John", "Doe",30};

funktioniert im ersten Beispiel.

Sie können nicht (im herkömmlichen Sinne) zuweisen eine Zeichenfolge in C

Die Stringliterale Sie haben („John“) in den Speicher geladen werden, wenn der Code ausgeführt wird. Wenn Sie ein Array mit einem dieser Literale initialisieren, wird die Zeichenfolge in einen neuen Speicherort kopiert. In Ihrem zweiten Beispiel kopieren Sie lediglich den Zeiger auf (Position von) dem Zeichenfolgenliteral. so etwas wie tun:

char* string = "Hello"; 
*string = 'C' 

verursachen könnte kompilieren oder Laufzeitfehler (Ich bin nicht sicher.) Es ist eine schlechte Idee, weil Sie die Zeichenkette „Hallo“ modifizieren, die zum Beispiel auf einem Microcontroller, angeordnet sein könnten im Nur-Lese-Speicher.

+0

Sie haben Recht, die von Ihnen geschriebene Zuweisung verursacht einen segfault, weil Sie versuchen, einen Zeigerwert zu ändern, aber wenn ich auf meine Beispieldinge verweise, geht das wie char * string = "Hello"; Zeichenfolge = "C"; (Beachten Sie, dass in der letzten Anweisung keine Zeigerzuweisung vorhanden ist), die wie erwartet funktioniert. –

+1

Ich möchte erwähnen, dass "Ändern eines Zeigerwerts" nicht unbedingt einen Segfault verursacht. Der Grund, dass das Snippet in meinem ursprünglichen Post einen segfault verursacht, liegt daran, dass Sie versuchen, Speicher zu ändern, der sich in einem eingeschränkten Adressraum befindet. – Gus

Verwandte Themen