Jede Funktion in <string.h> ist eine kleine Schleife über ein char-Array, die am Nullterminator stoppt. Sobald das klar ist, sieht die Bibliothek nicht mehr wie eine Liste kryptischer Namen aus, sondern wie die Handvoll Schleifen, die du selbst geschrieben hättest. Diese Seite behandelt die, die fast alle echte Arbeit tragen - und die Größenregeln, die sie davon abhalten, über das Ende deiner Puffer hinauszuschreiben.
Alles hier braucht ein Include:
#include <string.h>
strlen: wie viele Zeichen
strlen zählt Bytes bis zum Terminator, aber ohne ihn. Es liefert size_t, gib es also mit %zu aus.
strlen ist 6; sizeof ist 32. Das Erste ist der Text, das Zweite der Speicher - siehe Zeichenketten, warum diese Unterscheidung so wichtig ist.
strlen durchläuft bei jedem Aufruf die ganze Zeichenkette, setze es also nicht in eine Schleifenbedingung über dieselbe unveränderte Zeichenkette:
/* zählt die ganze Zeichenkette in jeder Iteration neu */
for (size_t i = 0; i < strlen(s); i++) { ... }
/* einmal zählen */
size_t n = strlen(s);
for (size_t i = 0; i < n; i++) { ... }
strcpy und strncpy: kopieren
strcpy(dst, src) kopiert die Zeichen plus den Terminator. Es hat keine Ahnung, wie groß dst ist, der Aufrufer muss also garantieren, dass dst mindestens strlen(src) + 1 Bytes fasst.
strncpy nimmt eine Höchstzahl entgegen, hat aber eine berühmte Falle: Ist die Quelle mindestens n Bytes lang, kopiert es genau n Zeichen und keinen Terminator. Terminiere immer selbst:
sizeof dst - 1 plus ausdrücklicher Terminator ist das Muster, das man sich merkt. (strncpy füllt kurze Quellen außerdem mit Nullen bis auf n Bytes auf, was bei großen Puffern verschwendete Arbeit ist - es wurde für Datensätze fester Breite entworfen, nicht für Sicherheit.)
strcat und strncat: verbinden
strcat(dst, src) hängt src an das Ende dessen, was bereits in dst steht. Das Ziel muss beide Zeichenketten plus einen Terminator fassen, und es muss bereits eine gültige Zeichenkette enthalten - an uninitialisierten Speicher anzuhängen ist undefiniertes Verhalten.
Beachte char path[64] = "/home/ada"; statt char path[64]; - der Initialisierer macht es zu einer gültigen Zeichenkette für das erste strcat.
strncat(dst, src, n) hängt höchstens n Zeichen an und fügt immer einen Terminator hinzu, n ist also der verbleibende Platz, nicht die gesamte Puffergröße:
strncat(dst, src, sizeof dst - strlen(dst) - 1);
Wiederholte strcat-Aufrufe durchsuchen das Ziel jedes Mal erneut nach seinem Ende. Eine lange Zeichenkette so in einer Schleife aufzubauen ist quadratisch; verfolge bei allem Nennenswerten deine eigene Schreibposition oder nimm snprintf, behandelt unter Zeichenkettenumwandlung.
strcmp: vergleichen
== vergleicht Adressen, es ist also für zwei verschiedene Arrays mit demselben Text falsch. strcmp vergleicht die Zeichen und liefert das Vorzeichen der Differenz.
Drei Regeln:
- Prüfe
strcmp(a, b) == 0auf Gleichheit.if (strcmp(a, b))zu schreiben bedeutet „wenn sie sich unterscheiden", was sich für fast jeden umgekehrt liest. - Nur das Vorzeichen ist definiert. Vergleiche das Ergebnis nicht mit
1oder-1. - Die Ordnung geht nach Bytewert,
"Zebra"sortiert in ASCII also vor"apfel". Für einen Vergleich ohne Beachtung der Groß-/Kleinschreibung mache beide Kopien zuerst klein - das oft gesehenestrcasecmpist eine POSIX-Erweiterung, kein Standard-C.
strncmp(a, b, n) vergleicht nur die ersten n Zeichen, was der saubere Weg ist, ein Präfix zu prüfen:
strchr und strstr: suchen
strchr(s, ch) findet das erste Vorkommen eines Zeichens; strrchr findet das letzte. strstr(heuhaufen, nadel) findet eine Teilzeichenkette. Alle drei liefern einen Zeiger in die ursprüngliche Zeichenkette oder NULL, wenn es keine Übereinstimmung gibt.
Den gelieferten Zeiger vom Anfang abzuziehen gibt den Index; sein Typ ist ptrdiff_t, ausgegeben mit %td. Weil das Ergebnis in das ursprüngliche Array zeigt, ist at + 1 der Rest der Zeichenkette ganz ohne Kopieren - ein sehr verbreitetes C-Idiom.
Prüfe immer auf NULL, bevor du dereferenzierst. strchr(email, '@') + 1 auf einer Zeichenkette ohne @ berechnet eine Adresse aus NULL, und das Programm ist nicht mehr definiert.
Eine Zeichenkette aufteilen
Es gibt keine Split-Funktion, aber strchr plus ein Terminator erledigt die Aufgabe an Ort und Stelle. Dieses Beispiel schneidet eine E-Mail in Benutzer und Domain:
memcpy kopiert eine genaue Byteanzahl, ohne sich um Terminatoren zu kümmern, und das willst du, wenn du die Länge bereits kennst. Der Terminator wird dann von Hand geschrieben.
Ein durchgearbeitetes Beispiel: einen Namen normalisieren
Die Tour zusammengebracht - trimmen, vergleichen, kopieren und verbinden:
Jeder Schreibzugriff ist durch das eigene sizeof des Ziels begrenzt, und auf jedes strncpy folgt ein ausdrücklicher Terminator. Diese Disziplin, konsequent angewandt, ist es, was C-Zeichenkettencode sicher macht.
Größenregeln, die man behalten sollte
strcpybrauchtstrlen(src) + 1freie Bytes im Ziel.strcatbrauchtstrlen(dst) + strlen(src) + 1.- Schreibe nach
strncpyselbstdst[n - 1] = '\0'. - Bei
strncatist die Anzahl der übrige Platz:sizeof dst - strlen(dst) - 1. - Prüfe
strchrundstrstraufNULL, bevor du das Ergebnis benutzt. - Benutze
sizeof dstnur, wenndstein echtes Array ist. Innerhalb einer Funktion, die einchar *dstentgegennimmt, liefertsizeofdie Größe des Zeigers - übergib die Pufferlänge als separaten Parameter.
Häufig gestellte Fragen
Was liefert strcmp in C?
Null, wenn die beiden Zeichenketten identisch sind, einen negativen Wert, wenn die erste vor der zweiten einsortiert wird, und einen positiven, wenn sie danach kommt. Nur das Vorzeichen ist bedeutsam - nimm nie an, dass es -1 oder 1 liefert. Der Test, den du willst, ist fast immer if (strcmp(a, b) == 0).
Warum kann ich Zeichenketten in C nicht mit == vergleichen?
a == b vergleicht die beiden Adressen, nicht die Zeichen. Zwei getrennte Arrays, die „Katze" halten, liegen an verschiedenen Adressen, der Vergleich ist also falsch, obwohl der Text übereinstimmt. Nimm strcmp(a, b) == 0 aus <string.h>.
Was ist der Unterschied zwischen strcpy und strncpy?
strcpy kopiert bis zum '\0' der Quelle, ohne zu wissen, wie groß das Ziel ist. strncpy stoppt nach höchstens n Bytes - ist die Quelle aber so lang, kopiert es keinen Terminator, du musst also selbst dst[n - 1] = '\0'; schreiben. Keines ist automatisch sicher; die Größendisziplin liegt bei dir.
Wie finde ich in C eine Teilzeichenkette?
strstr(heuhaufen, nadel) liefert einen Zeiger auf das erste Vorkommen oder NULL, wenn es keines gibt. Da es einen Zeiger in die ursprüngliche Zeichenkette liefert, gibt dir found - heuhaufen den Index. Nimm strchr, wenn du ein einzelnes Zeichen suchst.