Frage

Wenn ich ein std :: string mit einer Linie zu konstruieren, wie:

std::string my_string("a\0b");

Wo lese ich drei Zeichen im String haben wollen (a, null, b), ich nur einen. Was ist die richtige Syntax?

War es hilfreich?

Lösung

Da C ++ 14

Wir waren in der Lage wörtlichen std::string erstellen

#include <iostream>
#include <string>

int main()
{
    using namespace std::string_literals;

    std::string s = "pl-\0-op"s;    // <- Notice the "s" at the end
                                    // This is a std::string literal not
                                    // a C-String literal.
    std::cout << s << "\n";
}

Vor der C ++ 14

Das Problem ist der std::string Konstruktor, der eine const char* nimmt übernimmt die Eingabe eine C-Zeichenfolge ist. C-Strings werden \0 beendet und somit stoppt das Parsen, wenn es erreicht den \0 Charakter.

Um dies zu kompensieren, müssen Sie den Konstruktor verwenden, die die Zeichenfolge aus einem char-Array baut (keine C-String). Dies hat zwei Parameter - einen Zeiger auf das Array und eine Länge:

std::string   x("pq\0rs");   // Two characters because input assumed to be C-String
std::string   x("pq\0rs",5); // 5 Characters as the input is now a char array with 5 characters.

Hinweis: C ++ std::string ist nicht \0-terminierte (wie in anderen Beiträgen vorgeschlagen). Sie können jedoch einen Zeiger auf einen internen Puffer extrahieren, die einen C-String mit der Methode c_str() enthält.

Überprüfen Sie auch Doug T Antwort von weniger als etwa eine vector<char> verwendet wird.

Überprüfen Sie auch RIAD für eine C ++ 14-Lösung.

Andere Tipps

Wenn Sie tun, Manipulation, wie Sie mit einem C-String (Array von Zeichen) hielten mit

std::vector<char>

Sie haben mehr Freiheit, die sie wie ein Array in der gleichen Weise zu behandeln Sie einen c-string behandeln würden. Sie können copy () verwenden, um in eine Zeichenfolge zu kopieren:

std::vector<char> vec(100)
strncpy(&vec[0], "blah blah blah", 100);
std::string vecAsStr( vec.begin(), vec.end());

und Sie können es in vielen der gleichen Komponenten verwenden können Sie c-Strings verwenden

printf("%s" &vec[0])
vec[10] = '\0';
vec[11] = 'b';

Aber natürlich leiden unter den gleichen Problemen wie c-strings. Sie können Ihren null Terminal oder schreiben vorbei an dem zugewiesenen Raum vergessen.

Ich habe keine Ahnung Warum Sie würden wollen, so etwas zu tun, aber versuchen Sie dies:

std::string my_string("a\0b", 3);

Welche neuen Funktionen zu C fügen Literale benutzerdefinierte ++ eine elegante Antwort präsentiert:? definieren Sie

std::string operator "" _s(const char* str, size_t n) 
{ 
    return std::string(str, n); 
}

, dann können Sie Ihre Zeichenfolge auf diese Weise erstellen:

std::string my_string("a\0b"_s);

oder auch so:

auto my_string = "a\0b"_s;

Es gibt eine "alten Stil" Art und Weise:

#define S(s) s, sizeof s - 1 // trailing NUL does not belong to the string

, dann können Sie definieren

std::string my_string(S("a\0b"));

Im Folgenden wird funktionieren ...

std::string s;
s.push_back('a');
s.push_back('\0');
s.push_back('b');

Sie werden mit dieser vorsichtig sein. Wenn Sie mit einem beliebigen numerischen Zeichen ‚b‘ ersetzen, werden Sie lautlos die falsche Saite mit den meisten Methoden erstellen. . Siehe: Regeln für C ++ Stringliterale Escape-Zeichen

Zum Beispiel habe ich fiel diese unschuldig aussehenden Schnipsel in der Mitte eines Programms

// Create '\0' followed by '0' 40 times ;)
std::string str("\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", 80);
std::cerr << "Entering loop.\n";
for (char & c : str) {
    std::cerr << c;
    // 'Q' is way cooler than '\0' or '0'
    c = 'Q';
}
std::cerr << "\n";
for (char & c : str) {
    std::cerr << c;
}
std::cerr << "\n";

Hier ist, was dieses Programm Ausgabe für mich:

Entering loop.
Entering loop.

vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ

Das war meine erste print-Anweisung zweimal, mehrere nicht druckbare Zeichen, durch eine neue Zeile, gefolgt von etwas im internen Speicher, die ich gerade überschrieben haben (und dann gedruckt, die zeigen, dass sie überschrieben wurde). Am schlimmsten ist, auch diese Zusammenstellung mit gründlicher und ausführlicher gcc Warnungen mir keinen Hinweis auf etwas, falsch gab, und das Programm durch valgrind läuft nicht über irgendwelche falschen Speicherzugriffsmuster beschweren. Mit anderen Worten, es ist völlig unsichtbar durch moderne Werkzeuge.

Sie können das gleiche Problem mit dem viel einfacher std::string("0", 100); zu bekommen, aber das obige Beispiel ist ein wenig komplizierter und damit schwerer zu sehen, was los ist.

Zum Glück, C ++ 11 gibt ihnen eine gute Lösung für das Problem mit Initialisiererliste Syntax. Dies erspart Ihnen, die Anzahl der Zeichen angeben (die, wie ich oben zeigte, Sie falsch machen kann), und Zahlen entkommen vermeidet Vereinigen. std::string str({'a', '\0', 'b'}) ist sicher für jeden String Inhalt, im Gegensatz zu Versionen, die ein Array von char und einer Größe nehmen.

In C ++ 14 Sie können jetzt Literale verwenden

using namespace std::literals::string_literals;
std::string s = "a\0b"s;
std::cout << s.size(); // 3

Besser verwenden std :: vector , wenn diese Frage nicht nur für pädagogische Zwecke ist.

anonym Antwort ist ausgezeichnet, aber es gibt eine nicht-Makro-Lösung in C ++ 98 auch:

template <size_t N>
std::string RawString(const char (&ch)[N])
{
  return std::string(ch, N-1);  // Again, exclude trailing `null`
}

Mit dieser Funktion RawString(/* literal */) die gleiche Zeichenfolge wie S(/* literal */) produzieren:

std::string my_string_t(RawString("a\0b"));
std::string my_string_m(S("a\0b"));
std::cout << "Using template: " << my_string_t << std::endl;
std::cout << "Using macro: " << my_string_m << std::endl;

Darüber hinaus gibt es ein Problem mit dem Makro: Der Ausdruck ist nicht wirklich ein std::string wie geschrieben, und daher nicht verwendet werden kann, beispielsweise für die einfache Zuordnung-Initialisierung:

std::string s = S("a\0b"); // ERROR!

... so könnte es vorteilhaft sein, zu verwenden:

#define std::string(s, sizeof s - 1)

Natürlich sollten Sie nur eine oder die andere Lösung in Ihrem Projekt verwenden und nennen es, was auch immer Sie denken, angemessen ist.

Ich weiß, es ist eine lange Zeit diese Frage gestellt wurde. Aber für alle, die ein ähnliches Problem haben möglicherweise im folgenden Code interessiert sein.

CComBSTR(20,"mystring1\0mystring2\0")

Fast alle Implementierungen von std :: strings sind nullterminierten, so dass Sie wahrscheinlich nicht tun sollte. Beachten Sie, dass "a \ 0b" lang tatsächlich vier Zeichen ist wegen des automatischen Nullabschlusses (a, null, b, null). Wenn Sie das wirklich tun wollen und brechen std :: string Vertrag, können Sie tun:

std::string s("aab");
s.at(1) = '\0';

aber wenn Sie das tun, werden alle Ihre Freunde an Sie werden lachen, werden Sie nie das wahre Glück finden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top