AC-Zeichenfolge ist ein Zeichenarray, das mit einem Nullterminator endet .
Alle Zeichen haben einen Symboltabellenwert. Der Nullterminator ist der Symbolwert 0
(Null). Es wird verwendet, um das Ende einer Zeichenfolge zu markieren. Dies ist erforderlich, da die Größe der Zeichenfolge nirgendwo gespeichert wird.
Daher müssen Sie jedes Mal, wenn Sie Platz für eine Zeichenfolge zuweisen, ausreichend Platz für das Null-Abschlusszeichen einfügen. Ihr Beispiel tut dies nicht, es weist nur Platz für die 5 Zeichen von zu "hello"
. Richtiger Code sollte sein:
char str[6] = "hello";
Oder Sie können einen selbstdokumentierenden Code für 5 Zeichen plus 1 Nullterminator schreiben:
char str[5+1] = "hello";
Wenn Sie zur Laufzeit dynamisch Speicher für eine Zeichenfolge zuweisen, müssen Sie auch Platz für den Nullterminator zuweisen:
char input[n] = ... ;
...
char* str = malloc(strlen(input) + 1);
Wenn Sie am Ende einer Zeichenfolge keinen Nullterminator anhängen, funktionieren Bibliotheksfunktionen, die eine Zeichenfolge erwarten, nicht ordnungsgemäß und es treten Fehler mit "undefiniertem Verhalten" auf, z. B. Müllausgabe oder Programmabstürze.
Die gebräuchlichste Methode zum Schreiben eines Null-Abschlusszeichens in C ist die Verwendung einer sogenannten "oktalen Escape-Sequenz", die folgendermaßen aussieht : '\0'
. Dies entspricht zu 100% dem Schreiben 0
, \
dient jedoch als selbstdokumentierender Code, um anzugeben, dass die Null explizit als Nullterminator gedacht ist. Code wie if(str[i] == '\0')
prüft, ob das spezifische Zeichen der Nullterminator ist.
Bitte beachten Sie, dass der Begriff Nullterminator nichts mit Nullzeigern oder dem NULL
Makro zu tun hat ! Dies kann verwirrend sein - sehr ähnliche Namen, aber sehr unterschiedliche Bedeutungen. Aus diesem Grund wird der Nullterminator manchmal als NUL
mit einem L bezeichnet, nicht zu verwechseln mit NULL
oder Nullzeigern. Weitere Informationen finden Sie in den Antworten auf diese SO-Frage .
Das "hello"
in Ihrem Code wird als String-Literal bezeichnet . Dies ist als schreibgeschützte Zeichenfolge anzusehen. Die ""
Syntax bedeutet, dass der Compiler am Ende des Zeichenfolgenliteral automatisch einen Nullterminator anfügt. Wenn Sie also ausdrucken, erhalten sizeof("hello")
Sie 6, nicht 5, da Sie die Größe des Arrays einschließlich eines Nullterminators erhalten.
Es kompiliert sauber mit gcc
In der Tat nicht einmal eine Warnung. Dies liegt an einem subtilen Detail / Fehler in der C-Sprache, der es ermöglicht, Zeichenarrays mit einem Zeichenfolgenliteral zu initialisieren, das genau so viele Zeichen enthält, wie Platz im Array vorhanden ist, und dann den Nullterminator stillschweigend zu verwerfen (C17 6.7.9 / fünfzehn). Die Sprache verhält sich aus historischen Gründen absichtlich so. Weitere Informationen finden Sie unter Inkonsistente gcc-Diagnose für die Zeichenfolgeninitialisierung . Beachten Sie auch, dass C ++ hier anders ist und die Verwendung dieses Tricks / Fehlers nicht zulässt.
char str[] = "hello";
Fall erwähnen .char *str = "hello";
...str[0] = foo;
Problem.sizeof
auf die Verwendung für einen Funktionsparameter, insbesondere wenn dieser als Array definiert ist.Aus dem C-Standard (7.1.1 Begriffsbestimmungen)
In dieser Erklärung
Das String-Literal
"hello"
hat die interne Darstellung wiees hat also 6 Zeichen einschließlich der abschließenden Null. Seine Elemente werden verwendet, um das Zeichenarray zu initialisieren
str
nur Platz für 5 Zeichen reserviert.Der C-Standard (im Gegensatz zum C ++ - Standard) ermöglicht eine solche Initialisierung eines Zeichenarrays, wenn die abschließende Null eines Zeichenfolgenliteral nicht als Initialisierer verwendet wird.
Infolgedessen enthält das Zeichenarray
str
jedoch keine Zeichenfolge.Wenn Sie möchten, dass das Array eine Zeichenfolge enthält, können Sie schreiben
oder nur
Im letzten Fall wird die Größe des Zeichenarrays aus der Anzahl der Initialisierer des Zeichenfolgenliteral bestimmt, die gleich 6 ist.
quelle
Können alle Zeichenfolgen als Zeichenarray betrachtet werden ( Ja ), können alle Zeichenarrays als Zeichenfolgen betrachtet werden ( Nein)? )?
Warum nicht? und warum ist das wichtig?
Zusätzlich zu den anderen Antworten, die erklären, dass die Länge einer Zeichenfolge nirgendwo als Teil der Zeichenfolge gespeichert ist, und den Verweisen auf den Standard, in dem eine Zeichenfolge definiert ist, lautet die Kehrseite: "Wie behandeln die Funktionen der C-Bibliothek Zeichenfolgen?"
Während ein Zeichenarray dieselben Zeichen enthalten kann, handelt es sich lediglich um ein Zeichenarray, es sei denn, auf das letzte Zeichen folgt das nicht abschließende Zeichen. Das nicht endende Zeichen ermöglicht es, das Array von Zeichen als Zeichenfolge zu betrachten (zu behandeln).
Alle Funktionen in C, die eine Zeichenfolge als Argument erwarten, erwarten, dass die Zeichenfolge nicht abgeschlossen wird . Warum?
Dies hängt mit der Funktionsweise aller Zeichenfolgenfunktionen zusammen. Da die Länge nicht Teil eines Arrays ist, scannen Zeichenfolgenfunktionen im Array vorwärts, bis das Nullzeichen (z. B.
'\0'
- entspricht der Dezimalzahl0
) gefunden wird. Siehe ASCII-Tabelle und Beschreibung . Egal , ob Sie mitstrcpy
,strchr
,strcspn
, etc .. Alle verlassen String - Funktionen auf dem nul-Abschluss anwesend Charakter zu definieren , wo das Ende dieser Zeichenfolge ist.Ein Vergleich zweier ähnlicher Funktionen aus
string.h
wird die Bedeutung des nicht terminierenden Zeichens hervorheben . Nehmen Sie zum Beispiel:Die
strcpy
Funktion kopiert einfach Bytes vonsrc
bis,dest
bis das nicht abschließende Zeichen gefunden wird, das angibt ,strcpy
wo das Kopieren von Zeichen beendet werden soll. Nehmen Sie nun die ähnliche Funktionmemcpy
:Die Funktion führt eine ähnliche Operation aus, berücksichtigt oder erfordert jedoch nicht, dass der
src
Parameter eine Zeichenfolge ist. Damemcpy
beimsrc
Kopieren von Bytes nicht einfach vorwärts gescannt werden kann,dest
bis ein nicht abschließendes Zeichen erreicht ist, ist eine explizite Anzahl von Bytes zum Kopieren als dritter Parameter erforderlich. Dieser dritte Parameter liefertmemcpy
mit der gleichen Größe Informationenstrcpy
, die einfach durch Vorwärtsscannen abgeleitet werden können, bis ein nicht terminierendes Zeichen gefunden wird.(was auch betont, was in
strcpy
(oder einer Funktion, die eine Zeichenfolge erwartet) schief geht, wenn Sie der Funktion keine nicht terminierte Zeichenfolge zur Verfügung stellen - sie hat keine Ahnung, wo sie anhalten soll, und rast glücklich über den Rest Ihres Speichersegments davon Aufrufen von undefiniertem Verhalten, bis ein Nullzeichen zufällig irgendwo im Speicher gefunden wird - oder ein Segmentierungsfehler auftritt)Aus diesem Grund muss Funktionen, die eine nicht terminierte Zeichenfolge erwarten, eine nicht terminierte Zeichenfolge übergeben werden, und warum dies wichtig ist .
quelle
Intuitiv ...
Stellen Sie sich ein Array als Variable vor (enthält Dinge) und eine Zeichenfolge als Wert (kann in eine Variable eingefügt werden).
Sie sind sicherlich nicht dasselbe. In Ihrem Fall ist die Variable zu klein, um die Zeichenfolge aufzunehmen, sodass die Zeichenfolge abgeschnitten wird. ("Anführungszeichen" in C haben am Ende ein implizites Nullzeichen.)
Es ist jedoch möglich, eine Zeichenfolge in einem Array zu speichern, das viel größer als die Zeichenfolge ist.
Beachten Sie, dass die üblichen Zuweisungs- und Vergleichsoperatoren (
=
==
<
usw.) nicht wie erwartet funktionieren. Aber diestrxyz
Funktionsfamilie kommt ziemlich nahe, sobald Sie wissen, was Sie tun. Weitere Informationen finden Sie in den C-FAQ zu Zeichenfolgen und Arrays .quelle