strings und abschließende \0
-
Ich habe eine kurze Frage zu C-Strings und der abschließender '\0'.
Dieser Code funktioniert fehlerfrei:
char *str = "Hallo Welt!"; int len = strlen(str); //enthält nur die Länge von 'Hallo Welt!' printf("%s", str); //gibt die Zeichenkette fehlerfrei aus, obwohl //keine abschließende '\0' angefügt wurde.
Also nun meine Frage: Wann muss ich expliziet eine abschließende '\0' an eine Zeichenkette anfügen?
Danke
-
weil nur durch die \0 erkannt werden kann, wo der string endet.
im uebrigen siehst du an deinem beispielcode, dass der compiler und die standardfunktionen die \0-terminierung oft von selbst machen.
eigentlich zeigt str auf "Hallo Welt!\0", weil der compiler den string von selbst mit einer null terminiert.
auch strlen() braucht die \0, um das ende zu erkennen.
-
returns the number of characters in string, excluding the terminal NULL
-
Danke euch beiden!
c.rackwitz schrieb:
im uebrigen siehst du an deinem beispielcode, dass der compiler und die standardfunktionen die \0-terminierung oft von selbst machen.
Also muss ich im Prinzip wenn ich Benutzereingaben lese, oder aus Streams lese, die abschließende Null expliziet selber setzen?
-
nur manchmal, wenn du funktionen benutzt, die mit rohen daten arbeiten.
bei funktionen fuer strings musst du das nicht.gib doch bitte ein paar konkrete beispiele. so spekulativ laesst sich schwer helfen.
-
Ich würd mich nicht unbedingt darauf verlassen, dass die Funktionen den '\0' immer setzten. Ist mir schon häufiger passiert, dass wenn ich eine kürzere Kette in einen ehemals längere geschreiben hab, beim Ausgaben der Rest der längeren mit auftauchte. Kann jetzt aber nicht sagen bei welchen Funktionen.
-
alles steht in den dokumentationen.
-
imhotep schrieb:
Ich würd mich nicht unbedingt darauf verlassen, dass die Funktionen den '\0' immer setzten. Ist mir schon häufiger passiert, dass wenn ich eine kürzere Kette in einen ehemals längere geschreiben hab, beim Ausgaben der Rest der längeren mit auftauchte. Kann jetzt aber nicht sagen bei welchen Funktionen.
Häufiger Anfängerfehler ist z.B. strncpy() (natürlich auch strncmp() usw.).
strncpy() kopiert maximal n Zeichen. Wird n nicht erreicht, wird das Nullbyte vom Quellstring mitkopiert, aber wenn n erreicht wird, dann natürlich nicht!
also muß z.B. ein korrekter strncpy()-Aufruf so aussehen:
char buf[1024]; strncpy( buf, quelle, 30 ); buf[30] = '\0'; // <--
mit der letzten Anweisung wird sichergestellt, daß der String im Puffer auf jeden Fall null-terminiert ist.
Anderes Beispiel (in "Id***enparsern" oft verwendet):
if ( strncmp( buf, "ABC", 3 ) == 0 ) xxxxx
Dabei wird oft übersehen, daß der String nach "ABC" ja noch weitergehen kann.
Das führt in solchen "Parsern" oft dazu, daß z.B. "GO" gleich "GOTO" ist usw.
EDIT:
Mir ist noch was eingefallen: Es gibt Leute, die meinen, in einem Puffer mehrere Strings ablegen zu müssen, z.B. so:
char* func( char* buf ) { char* p = strchr( buf, '\0' ) + 1; strcpy( p, "hallo" ); return p; }
Das ist praktisch die Garantie für einen Puffer-Überlauf. Vor allem, wenn dem Programmierer nicht klar war, wann und wo die Funktion aufgerufen wird. Dies führt zu extrem instabilem Code, den man kaum noch warten kann, vor allem wenn solche Konstruktionen mehrere hundertmal vorkommen.
-
imhotep schrieb:
Ich würd mich nicht unbedingt darauf verlassen, dass die Funktionen den '\0' immer setzten. Ist mir schon häufiger passiert, dass wenn ich eine kürzere Kette in einen ehemals längere geschreiben hab, beim Ausgaben der Rest der längeren mit auftauchte. Kann jetzt aber nicht sagen bei welchen Funktionen.
Man muss nur die Dokumentation von den Funkionen genau lesen. (Ich meine jetzt damit, Funktionen die mit Strings arbeiten). Denn in der Doku steht genau, ob die Funktion mit \0 oder ohne \0 zurückliefern.
In der Regel liefern die meisten string Funktionen immer 0-terminierende Strings. Nur solche Funktionen, die mit festen Längen arbeiten, wie strncpy, strncat (eben diese Funktionen mit dem "n" in der Mitte) liefern keine 0-terminierende Strings, aus Sicherheitsgründen würde ich sagen.
Funktionen wie memmove, memcpy usw liefern auch keine 0-terminierende Strings, weil sie eigentlich nicht auschließlich Strings Funktionen sind (obwohl sie in string.h definiert sind) sondern können jeden Buffer kopieren, da diese Funktionen void* und nicht char* erwarten. Aus diesem Grund wäre natürlich nicht richtig einfach \0 zu setzen.
In der Regel sollte man immer einen Blick in die Doku der gewünschten Funktion werfen, dort steht immer, (sollte zumindest) ob \0 zurückgeliefert wird oder nicht. Ansonsten:
man: memchr(3)
Zum Suchen eines Zeichens (nicht unbedingt Strings)man: memcmp(3)
Zum Vergliechen (nicht unbedingt Strings)man: memcpy(3)
Zum Kopieren von Zeichen (nicht unbedingt Strings)man: memmove(3)
Zum Kopieren von Zeichen (nicht unbedingt Strings)man: memset(3)
Zum Belegen eines Puffers mit einem Zeichen (nicht unbedingt Strings)man: strcat(3)
Um Strings hintereinander anhängenman: strncat(3)
Um Strings hintereinander anhängenman: strchr(3)
Zum Suchen eines Zeichens in einem Stringsman: strrchr(3)
Zum Suchen eines Zeichens in einem Stringsman: strcoll(3)
ähnliche wie strcmpman: strcpy(3)
Um Zeichenketten zu kopierenman: strncpy(3)
Um Zeichenketten zu kopierenman: strcspn(3)
Berechnet die Länge von Teilzeichenkettenman: strerror(3)
Liefert die Fehlerbeschreibung zu einer Fehlernummer (siehe man: errno)man: strlen(3)
Liefert die Länge eines Stringsman: strcmp(3)
Um Strings zu vergleichenman: strncmp(3)
Um Strings zu vergleichenman: strpbrk(3)
Zum Suchen von Zeichenketten in anderen Zeichenkettenman: strspn(3)
Berechnet die Länge von Teilzeichenkettenman: strstr(3)
Zum Suchen von Zeichenkettenman: strtok(3)
Zur Trennung von Zeichenketten durch Terminalsymbole.man: strxfrm(3)
Viel zu schwer in kürzen Worten zu fassen.
-
Danke - Ihr habt mir schon beim Verständnis viel weitergeholfen!