2012-06-08 4 views
17

In vielen Codebeispiele verwenden die Menschen in der Regel '\0' nach einer neuen char Array wie folgt zu erstellen:Warum werden Zeichenfolgen in C++ normalerweise mit ' 0' beendet?

string s = "JustAString"; 
char* array = new char[s.size() + 1]; 
strncpy(array, s.c_str(), s.size()); 
array[s.size()] = '\0'; 

Warum wir '\0' hier verwenden sollten?

+12

cstrings sind normalerweise nicht die beste Idee in C++ - Code –

+0

C-String, der im Wesentlichen ein Char-Array ist, muss NUL terminiert werden. Andernfalls funktionieren die Funktionen in 'string.h' nicht wie erwartet. – nhahtdh

+3

In C sehen Sie das sehr oft. In C++ gibt es wahrscheinlich bessere Möglichkeiten, das Gleiche zu erreichen. – jedwards

Antwort

40

Der Titel Ihrer Frage verweist auf C-Zeichenfolgen. C++ std::string Objekte werden anders behandelt als Standard C Zeichenfolgen. \0 ist wichtig, wenn C-Strings verwenden, und wenn ich den Begriff string hier verwende, meine ich Standard-C-Strings.

\0 wirkt als String-Terminator in C. Es wird als die Nullzeichen bekannt oder NUL. Es signalisiert Code, der Strings verarbeitet - Standardbibliotheken, aber auch eigenen Code - wo das Ende eines Strings ist. Ein gutes Beispiel ist strlen, die die Länge einer Zeichenfolge zurückgibt.

Wenn Sie deklarieren einen konstanten String mit:

const char *str = "JustAString"; 

dann wird die \0 für Sie automatisch angehängt. In anderen Fällen, in denen Sie eine nicht konstante Zeichenfolge wie in Ihrem Array-Beispiel verwalten, müssen Sie sich manchmal selbst darum kümmern. Die docs for strncpy, die in Ihrem Beispiel verwendet wird, sind eine gute Illustration: strncpy Kopien über die null Terminierungszeichen außer in dem Fall, wo die angegebene Länge erreicht wird, bevor die gesamte Zeichenfolge kopiert wird. Daher sehen Sie oft strncpy kombiniert mit der möglicherweise redundante Zuweisung eines Nullabschlusses. strlcpy und strcpy_s wurden entwickelt, um die möglichen Probleme zu beheben, die sich aus der Vernachlässigung dieses Falles ergeben.

In Ihrem speziellen Beispiel ist array[s.size()] = '\0'; eine solche Redundanz: da array der Größe ist s.size() + 1 und strncpy kopiert s.size() Zeichen, wird die Funktion der \0 anhängen.

Die Dokumentation für Standard-C-Zeichenfolgen-Dienstprogramme zeigt an, wann Sie vorsichtig sein müssen, um einen solchen Null-Terminator einzubinden. Aber lesen Sie die Dokumentation sorgfältig durch: Wie bei strncpy werden die Details leicht übersehen, was zu potentiellen Pufferüberläufen führt.

+0

Also, wie sind Zeichenketten in C++ beendet? Ich habe herausgefunden, dass sie nicht NULL-terminiert sind, weil das Hinzufügen von '\ 0' bei jedem beliebigen Index die Zeichenfolge nicht wie in C trimmt, sondern nur den Index in der Zeichenfolge durch ein leeres Zeichen ersetzt. – CaptainDaVinci

+0

@CaptainDaVinci Sie werden nicht notwendigerweise beendet, da die Länge intern gespeichert wird. Wenn Sie 'c_str()' aufrufen, erhalten Sie einen ordnungsgemäß terminierten Puffer, aber nur, weil Sie gut gefragt haben. – tadman

13

Warum werden Strings in C++ normalerweise mit '\0' terminiert?

Beachten Sie, dass C++ - Zeichenfolgen und C-Zeichenfolgen nicht identisch sind.
In C++ - Zeichenfolge bezieht sich auf std::string, die eine Vorlagenklasse ist und eine Vielzahl von intuitiven Funktionen bietet, um die Zeichenfolge zu behandeln.
Beachten Sie, dass C++ std :: string nicht \0 beendet ist, aber die Klasse bietet Funktionen zum Abrufen der zugrunde liegenden Zeichenfolge Daten als \0 beendet C-Stil-Zeichenfolge.

In C ist eine Zeichenfolge eine Sammlung von Zeichen. Diese Sammlung endet normalerweise mit einer \0.
Wenn kein spezielles Zeichen wie \0 verwendet wird, gibt es keine Möglichkeit zu wissen, wann eine Zeichenfolge endet.
Es ist auch als String-Null-Terminator bekannt.

Ofcourse, könnte es andere Möglichkeiten der Buchhaltung sein, die Länge der Zeichenfolge zu verfolgen, aber ein Sonderzeichen mit zwei gerade Vorteile:

  • Es ist intuitiver und
  • Es gibt keine zusätzliche Gemeinkosten

Beachten sie, dass \0 erforderlich ist, weil die meisten Standard-C-Bibliothek Funktionen auf Strings arbeiten vorausgesetzt, sie sind \0 beendet.
Zum Beispiel:
Während printf() verwenden, wenn Sie eine Zeichenfolge haben, die dann nicht \0 beendet wird printf() Zeichen stdout bis ein \0 hält, könnte Müll sogar drucken Sie es kurz begegnet schreibt.

Warum sollten wir '\0' hier verwenden?

Es gibt zwei Szenarien, wenn Sie nicht brauchen, um \0 kündigen einen String:

  • In jeder Nutzung, wenn Sie ausdrücklich Buchhaltung Länge der Zeichenfolge und
  • sind Wenn Sie einige Standards verwenden library api fügt implizit eine Zeichenfolge \0 hinzu.

In Ihrem Fall haben Sie bereits das zweite Szenario für Sie arbeiten.

array[s.size()] = '\0'; 

Die obige Code-Anweisung ist in Ihrem Beispiel redundant.

Für Ihr Beispiel mit strncpy() macht es nutzlos. strncpy() kopiert s.size() Zeichen zu Ihrem array, Beachten Sie, dass es einen Nullabschluss anfügt, wenn noch Platz nach dem Kopieren der Zeichenfolgen übrig ist. Da array von der Größe s.size() + 1 ist, wird automatisch eine \0 hinzugefügt.

+1

Nicht unbedingt. Sie können auch ein Arbitrary-Length-Array speichern, indem Sie die Länge irgendwo halten (wie Java funktioniert. Ich nehme an). –

+0

@ BrendanLong: Hoffe, dass die Antworten. –

+0

@BrendanLong Ich gehe davon aus, dass der Bearbeitungsvorgang nach diesem Kommentar ausgeführt wurde, aber wie bereits erwähnt, wird dadurch zusätzlicher Aufwand vermieden. Um es so zu machen, wie Sie es vorschlagen, müssten Sie eine Struktur mit einem int sowie dem Array erstellen, die eine schlechtere Performance bietet und mehr Speicher verbraucht. – evanmcdonnal

6

'\ 0' ist das Null-Beendigungszeichen. Wenn Ihr Zeichen-Array es nicht hatte und Sie versuchten, einen strcpy zu machen, hätten Sie einen Pufferüberlauf. Viele Funktionen verlassen sich darauf, um zu wissen, wann sie aufhören müssen, Speicher zu lesen oder zu schreiben.

2

In C stellen wir eine Zeichenfolge mit einem Array von char (oder w_char) dar und verwenden ein Sonderzeichen, um das Ende der Zeichenfolge zu signalisieren. Im Gegensatz zu Pascal, das die Länge der Zeichenfolge im Index 0 des Arrays speichert (daher hat die Zeichenfolge eine harte Grenze für die Anzahl der Zeichen), gibt es theoretisch keine Begrenzung für die Anzahl der Zeichen, die eine Zeichenfolge ((dargestellt als Zeichenarray) kann in C enthalten sein.

Das Sonderzeichen wird in allen Funktionen der Standardbibliothek in C und auch in anderen Bibliotheken als NULL erwartet.Wenn Sie die Bibliotheksfunktionen verwenden möchten, die auf der genauen Länge der Zeichenfolge basieren, müssen Sie die Zeichenfolge mit NUL beenden. Sie können Ihr eigenes abschließendes Zeichen völlig definieren, aber Sie müssen verstehen, dass Bibliotheksfunktionen, die String (als Array von Zeichen) enthalten, möglicherweise nicht wie erwartet funktionieren und alle Arten von Fehlern verursachen.

In dem Codefragment muss das abschließende Zeichen explizit auf NUL gesetzt werden, da Sie nicht wissen, ob im Array Aliasdaten vorhanden sind. Es ist auch eine gute Übung, da in großen Code möglicherweise die Initialisierung des Zeichenarrays nicht angezeigt wird.

3
strncpy(array, s.c_str(), s.size()); 
array[s.size()] = '\0'; 

Warum sollten wir hier '\ 0' verwenden?

Sie sollten nicht, diese zweite Linie ist Platzverschwendung. strncpy fügt bereits eine Null-Terminierung hinzu, wenn Sie wissen, wie Sie es verwenden können. Der Code kann neu geschrieben werden als:

strncpy(array, s.c_str(), s.size()+1); 

Strncpy Art einer seltsamen Funktion ist, es wird davon ausgegangen, dass der erste Parameter ist ein Feld von der Größe des dritten Parameters. Es kopiert also nur die Null-Beendigung, wenn nach dem Kopieren der Strings noch Platz übrig ist.

Sie könnten auch memcpy() in diesem Fall verwendet haben, wird es etwas effizienter sein, obwohl vielleicht macht der Code weniger intuitiv zu lesen.

+0

oder andersherum, macht es so komisch, dass der Code weniger intuitiv ist als das einfache Memcpy. Aber wenn ich Code sehe, wie oben gezeigt, ist mein erster Reflex in der Regel zu überprüfen, ob das Kopieren von Daten in ein Array nicht vollständig durch direkte Verwendung von c_str() Inhalt vermieden werden kann, da die letzte Null oft Strings hinzugefügt wird, die später nicht modifiziert werden (Ausgabezeichenfolgen) – kriss

Verwandte Themen