2016-06-13 8 views
-7

Wie ich verstehe es C-Strings, auch wenn in C++ anstelle der String-Klasse verwendet wird, müssen ein Nullabschlusszeichen:Warum fungiert ein C++ - Zeiger auf ein Zeichen als Zeichenfolge, obwohl kein Nullabschluss vorhanden ist?

This is a string.\0 

Es ist mein Verständnis, dass das Fehlen eines Null-Zeichen bewirkt, dass das Programm nach dem String weiterlesen, was in den Speicher kommt, bis es die Binärdarstellung des Nullzeichens findet. Dies ist ein sehr eindeutig undefiniertes Verhalten.

Wenn ich eine dtoi-Funktion schreibe (ich wollte dies selbst schreiben für die Praxis als Teil eines anderen Übungsprojekts, das ich mache - ich weiß, dass es Bibliothekseinrichtungen dafür gibt), habe ich ein anderes Verhalten gefunden Erstellen der Zeichenfolge für die invalid_argument Ausnahme).

int dtoi(const char d){ 
    switch(d){ //using switch statement rather than d-'0' to support character sets with non-consecutive digits or digits that go from 9 to 0 rather than 0 to 9 
     case '0': 
      return 0; 
     case '1': 
      return 1; 
     case '2': 
      return 2; 
     case '3': 
      return 3; 
     case '4': 
      return 4; 
     case '5': 
      return 5; 
     case '6': 
      return 6; 
     case '7': 
      return 7; 
     case '8': 
      return 8; 
     case '9': 
      return 9; 
     default: 
      throw invalid_argument(((d == '\0') ? "null character" : &d) + string(" is not a valid digit character.")); 
    } 
} 

Als Null-Zeichen zu Beginn der Ausnahme Zeichenfolge verursachte es beim ersten Zeichen zu beenden (dh., Wenn ein Null-Zeichen meiner Implementierung von dtoi geben wurden), habe ich beschlossen, es zu haben, um den Text anzuzeigen "null character" anstatt das Zeichen direkt einzufügen, wenn es '\0' ist. Um dies zu implementieren, verwende ich den bedingten Operator. Ich kann (d == '\0') ? "null character" : d nicht verwenden (beachten Sie, wie es d nicht &d am Ende sagt), da der bedingte Operator dann entweder einen Zeiger auf das erste Zeichen in dem Zeichenfolgenliteral oder direkt ein Zeichen zurückgeben kann. Um zu sehen, was passiert ist, habe ich mich entschieden, &d auszuprobieren, und zu meiner Überraschung hat es gedruckt, welches Zeichen in der Funktion in exception.what() übergeben wurde. Ich würde erwarten, dass es einen Zeiger auf das übergebene Zeichen liefert, aber dann weiter in einen zufälligen Speicher liest, bis es ein Nullzeichen gefunden hat. Ich habe das mehrfach mit mehreren verschiedenen Zeichen versucht. Warum verhält es sich so? Habe ich eigentlich recht, dass es ein undefiniertes Verhalten ist, und es funktioniert einfach so, wie es hier beabsichtigt ist?

+2

Weil undefined Verhalten. – juanchopanza

+1

Für jeden, der eine Absage macht: Ich bin mir nicht sicher, warum Sie das tun - es scheint eine gültige Frage zu sein. Ich frage, ob eine bestimmte Aktion tatsächlich ein undefiniertes Verhalten ist oder ob ich falsch verstehe, wie C++ funktioniert. Wenn das irgendwie ungültig ist, sag es mir lieber, als dass du mir eine Bewertung gibst. – john01dav

+0

@juanchopanza Das klingt sehr nach einer Antwort. – john01dav

Antwort

2

This operator+ wird hier verwendet (ein Zeiger auf einzelne char, die nicht nullterminiert ist, ist nicht wirklich geeignet). Ja, auf jeden Fall undefined behavior.

lhs - Zeichenfolge, Zeichen, oder einen Zeiger auf das erste Zeichen in einem null-terminierte Array

Gerade std::string machen die allgemeine Art, es zu beheben:

((d == '\0') ? std::string("null character") : std::string(1, d)) 

Und bilden Sie keine switch - case Aussagen wie diese.

+0

Danke für die Antwort. Ich habe jedoch eine Frage, was ist falsch an meinem Schaltkasten? Liegt es einfach daran, dass der Standard 0-9 als garantiert definiert? Wenn ja, wie sollte ich eine Ausnahme für ungültige Eingaben implementieren? – john01dav

+0

@ john01dav T.C. und M.M erklärt. Sie werden mit 'd - '0'' und einigen' if'-Anweisungen zufrieden sein. – LogicStuff

3

Es gibt eine grundlegende Sache, die Sie über C-Style-Strings wissen müssen, die Art, wie wir sie darstellen (Char-Array mit einem '\ 0' am Ende) ist nur eine Konvention, es gibt keinen Typ (in C) für Saiten. Dies bedeutet, dass aus sprachlicher Sicht kein Unterschied zwischen einem Zeiger auf ein einzelnes Zeichen und einem Zeiger auf den Anfang eines Zeichenfelds besteht (das eine Zeichenfolge sein kann). Es ist also eine Funktion, einen solchen Zeiger zu verwenden, um ihn gut zu interpretieren, und diese Dokumentation ist dein Freund.

Da Sie C++ verwenden, rate ich Ihnen dringend, nur std :: string zu verwenden und C-Style-Strings für die Rückwärtskompatibilität mit C-Bibliotheken zu behalten, Sie werden viele Probleme vermeiden.

0

Ja, es ist undefiniertes Verhalten, weil Sie zufällig Speicher lesen.Was Sie anstelle der ganzen unordentlichen Schalter und der ?: Operator tun sollten, ist dies:

#include <cctype> 

if(!std::isdigit(d)) 
{ 
    std::string err_str; 

    if(d == '\0') 
    { 
    err_str = "Null character"; 
    } 
    else 
    { 
    err_str = std::string(1, d); 
    } 
    err_str += " is not a valid digit character."; 

    throw invalid_argument(err_str); 
} 

return (int)d - '0'; 
Verwandte Themen