Icon Ressource

[C] Strings? Aufbau, Missverständnisse und Pitfalls

Vorab
Der Grund, warum ich diesen Beitrag schreibe, ist, dass das Arbeiten mit C-Strings immer wieder zu Verwirrungen führt. Hauptgrund dafür ist, dass meistens davon ausgegangen wird, ein C-String würde sich ähnlich verhalten wie Basistypen (char, int, float, ...). Das ist falsch! Wenn man also von einem C-String redet, ist das eigentlich schon verwirrend genug, da das den Anschein erweckt, es wäre ein eigener Typ. C kennt keinen Stringtyp.

Was ist dann aber ein String in C?
Die Repräsentation eines C-Strings ist die eines Arrays von char-Werten, mit dem Zusatz, dass immer(!) ein zusätzliches Element mit dem Wert 0 vorhanden ist, das das Ende eines C-Strings markiert. Dieses Element wird auch Nullterminierung genannt. Alle C-Funktionen, die komplette C-Strings verarbeiten, lesen diese char-weise, bis sie auf die Nullterminierung treffen und brechen dort ab.

Aber sehen wir uns das an einem Beispiel an. Gegeben sei ein C-String "abc" mit folgender Deklaration und Initialisierung
char str[] = "abc";
Wie liegt dieser String nun im Speicher vor? Eine schematische Darstellung sollte zum Verständnis beitragen ...
1586206977586.png

Zunächst ist zu sehen, dass die Nullterminierung in diesem Fall automatisch gesetzt wurde. Das ist eine Besonderheit in der C Syntax. Wenn eine Zeichenkette in Anführungszeichen steht, beinhaltet sie implizit die Nullterminierung. Ebenso wird die Größe des benötigten Speicherplatzes automatisch bestimmt, wenn kein Wert bei der Deklaration in den eckigen Klammern angegeben wird.
Das Array hat 4(!) Elemente, auf die mit den Indizes 0 bis 3 zugriffen werden kann. Die Indizes 0, 1 und 2 verweisen dabei auf die chars 'a', 'b' und 'c'. Der Index 3 verweist auf die Nullterminierung. Der Index 4 würde bereits auf ungültigen Speicher verweisen.

Falsch wäre eine Initialisierung
char str[3] = "abc";
da das Array str nicht groß genug ist, um die Nullterminierung zu beinhalten, denn würde man eine Array-Initialisierung verwenden, dann wäre das Äquivalent
char str[3] = {'a', 'b', 'c', '\0'};
Hier wird der Fehler offensichtlich: Das Array ist für 3 Elemente deklariert, es sollen aber 4 initial zugewiesen werden.

Auch richtig wäre
char str[4] = "abc";
da das Array str groß genug ist, um die Nullterminierung zu beinhalten.

Öfter deklariert man aber einen Puffer der mindestens die Größe der erwarteten Zeichenkette + Nullterminierung hat. Bspw.
char buffer[256] = {0};
Die Initialisierung mit {0} sorgt hier dafür, dass die Elemente nicht zufällige Werte enthalten. Sie haben alle den Wert '\0', was nützlich sein kann wenn man anschließend den einzelnen Elementen zeichenweise einen Wert zuweist. Das nachfolgende Element enthält dann automatisch die Nullterminierung.


Wie gehen nun die C Funktionen bei der Verarbeitung vor?
Im Regelfall wird ein char-Pointer auf das erste Element erwartet. Der Bezeichner eines Arrays (im Beispiel str) ist gleichzeitig ein Pointer auf das erste Element des Arrays. Er enthält die Speicheradresse (im Beispiel 0020A50521331000). Die C Funktionen starten bei dieser Adresse und lesen ein Zeichen (im Beispiel 'a'), danach wird der Pointerwert (=Speicheradresse) um die Breite eines char in Bytes (=1) inkrementiert und das nächste Zeichen gelesen. Das wird so lange wiederholt, bis das erste '\0'-char (=Nullterminierung) gelesen wurde. An dieser Stelle wird das Lesen abgebrochen.


Häufige Missverständnisse und Fehler:

  • Die strlen() Funktion gibt die Länge eines C-Strings zurück. Dabei wird die Nullterminierung nicht mitgezählt. Verwendet man allerdings den zurückgegebenen Wert als Index auf das Array, dann verweist dieser Index auf die Nullterminierung (da Array-Indizes bei 0 starten).
  • Ein char* ist noch kein Puffer für einen C-String. Er muss auf einen ausreichend großen Speicherbereich zeigen. Also muss entweder ein Array deklariert oder Speicher bspw. per malloc()/calloc() reserviert werden.
  • Bei der Deklaration/Allokation von Pufferarrays für C-Strings ist darauf zu achten, dass der Platz für die Nullterminierung berücksichtigt ist.
  • C-Strings lassen sich nicht durch den = Operator einer Variablen zuweisen. Einzige Ausnahme ist die Initialisierung mit einem Stringliteral. Nutze statt dessen die dafür vorgesehenen Funktionen, wie strcpy(), strncpy(), memcpy(), ...
  • Bei der Nutzung von C-Funktionen für das Kopieren von Zeichenfolgen, ist darauf zu achten, ob oder in welchem Fall diese automatisch die Nullterminierung hinzufügen oder nicht. Es ist ratsam, sich bei Unklarheiten eine entsprechende Funktionsreferenz anzusehen. Ggf. muss die Nullterminierung separat gesetzt werden.
  • Werden Zeichenfolgen char-weise in einem Puffer aufgebaut (beispielsweise in einer Schleife), muss im Anschluss die Nullterminierung angehängt werden.
  • C-Strings lassen sich nicht mit den Operatoren ==, !=, <=, <, >= oder > vergleichen. Hier würden lediglich Pointerwerte (Speicheradressen) miteinander verglichen werden. Nutze die strcmp() Funktion.
  • Like
Reaktionen: Zhavok und BAGZZlash
Autor
german
Aufrufe
3.043
Erstellt am
Letzte Bearbeitung
Bewertung
0,00 Stern(e) 0 Bewertung(en)

Weitere Ressourcen von german

Zurück
Oben Unten