質問

次のような行でstd :: stringを構築する場合:

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

結果の文字列に3つの文字(a、null、b)が必要な場合、1つしか取得できません。適切な構文は何ですか?

役に立ちましたか?

解決

C ++ 14以降

リテラルstd::string

を作成できました
#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";
}

C ++ 14より前

問題は、入力がC文字列であると想定するconst char*を取る\0コンストラクターです。 C文字列はc_str()で終了するため、vector<char>文字に達すると解析が停止します。

これを補正するには、char配列(C-Stringではなく)から文字列を構築するコンストラクターを使用する必要があります。これには、配列へのポインターと長さの2つのパラメーターが必要です。

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.

注:C ++ <=>は NOT <=>で終了しています(他の投稿で示唆されています)。ただし、メソッド<=>を使用して、C-Stringを含む内部バッファーへのポインターを抽出できます。

Doug Tの回答以下の<=>の使用について。

C ++ 14ソリューションについては、 RiaD もご覧ください。

他のヒント

Cスタイルの文字列(charsの配列)のように操作を行う場合は、使用を検討してください

std::vector<char>

c-stringを扱うのと同じ方法で、配列のように扱う自由度があります。 copy()を使用して文字列にコピーできます:

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

そして、あなたはc-stringsを使うことができる同じ場所の多くでそれを使うことができます

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

ただし、当然ながら、C文字列と同じ問題に悩まされます。 nullターミナルを忘れるか、割り当てられたスペースを超えて書き込みます。

このようなことをしたいのかなぜわからないが、これを試してください:

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

ユーザー定義リテラルがC ++に追加する新しい機能は何ですか?はエレガントな答えを示します:定義

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

この方法で文字列を作成できます:

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

またはそうであっても:

auto my_string = "a\0b"_s;

<!> quot;古いスタイル<!> quot;方法:

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

その後、定義できます

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

次のように動作します...

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

これには注意する必要があります。 'b'を数字に置き換えると、ほとんどの方法を使用して間違った文字列を静かに作成します。参照: C ++文字列リテラルのエスケープ文字のルール

たとえば、この無邪気なスニペットをプログラムの途中で落としました

// 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";

このプログラムが出力する内容は次のとおりです。

Entering loop.
Entering loop.

vector::_M_emplace_ba
QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ

それは私の最初の印刷ステートメントで、いくつかの非印刷文字、改行、内部メモリ内の何かが続き、上書きしました(そして印刷され、上書きされたことを示します)。最悪なのは、徹底的かつ詳細なgccでコンパイルすることですら警告は、何か問題があることを示すものではなく、valgrindを介してプログラムを実行しても、不適切なメモリアクセスパターンについて文句を言うことはありませんでした。つまり、最新のツールではまったく検出できません。

はるかに単純なstd::string("0", 100);でもこの同じ問題が発生しますが、上記の例は少し複雑であるため、何が間違っているのかを確認するのが難しくなります。

幸いなことに、C ++ 11は初期化リストの構文を使用して問題を解決します。これにより、文字数を指定する必要がなくなり(上で示したように、間違った操作を行うことができます)、エスケープされた数字を結合する必要がなくなります。 std::string str({'a', '\0', 'b'})は、charおよびサイズの配列を取るバージョンとは異なり、すべての文字列コンテンツに対して安全です。

C ++ 14では、リテラルを使用できるようになりました

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

std :: vector <!> lt; char <!> gt;を使用する方が良いこの質問が教育目的だけのものではない場合。

anonymの答えは優れていますが、C ++ 98には非マクロソリューションもあります:

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

この関数を使用すると、RawString(/* literal */)S(/* literal */)と同じ文字列を生成します:

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;

さらに、マクロに問題があります。式は実際には記述されているようにstd::stringではないため、使用できません。単純な代入初期化の場合:

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

...そのため、使用することをお勧めします:

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

明らかに、プロジェクトではどちらか一方のソリューションのみを使用し、適切と思われるものを呼び出す必要があります。

この質問は長い間聞かれています。しかし、同様の問題を抱えている人なら、次のコードに興味があるかもしれません。

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

std :: stringsのほとんどすべての実装はnullで終了するため、おそらくこれを行うべきではありません。 <!> quot; a \ 0b <!> quot;自動nullターミネータ(a、null、b、null)のため、実際には4文字の長さです。本当にこれを実行してstd :: stringのコントラクトを解除したい場合は、次の操作を実行できます。

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

しかし、もしそうなら、あなたのすべての友人はあなたを笑うでしょう、あなたは本当の幸せを決して見つけることはありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top