Menu

Zeichenkettenfunktionen in C: strlen, strcpy, strcat, strcmp und mehr

Eine praktische Tour durch <string.h>: messen mit strlen, kopieren mit strcpy und strncpy, verbinden mit strcat, vergleichen mit strcmp, suchen mit strchr und strstr - und wie man Puffer so bemisst, dass keine davon überläuft.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

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) == 0 auf 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 1 oder -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 gesehene strcasecmp ist 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

  • strcpy braucht strlen(src) + 1 freie Bytes im Ziel.
  • strcat braucht strlen(dst) + strlen(src) + 1.
  • Schreibe nach strncpy selbst dst[n - 1] = '\0'.
  • Bei strncat ist die Anzahl der übrige Platz: sizeof dst - strlen(dst) - 1.
  • Prüfe strchr und strstr auf NULL, bevor du das Ergebnis benutzt.
  • Benutze sizeof dst nur, wenn dst ein echtes Array ist. Innerhalb einer Funktion, die ein char *dst entgegennimmt, liefert sizeof die 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.

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S