言うと...
std::string x = "hello";
`string`から` char * `または` const char * `を取得する
x
スコープ内にあり、さらに変更されていないときに有効な文字ポインターを取得する方法
C ++ 11は物事を簡素化します。以下はすべて同じ内部文字列バッファへのアクセスを提供します:
const char* p_c_str = x.c_str();
const char* p_data = x.data();
char* p_writable_data = x.data(); // for non-const x from C++17
const char* p_x0 = &x[0];
char* p_x0_rw = &x[0]; // compiles iff x is not const...
上記のすべてのポインタは同じ値、つまりバッファの最初の文字のアドレスを保持します。C ++ 11は、明示的に割り当てられた文字列コンテンツの後に常に追加のNUL / 0ターミネーター文字を保持することを保証しているため(たとえばstd::string("this\0that", 9)
、バッファーがを保持するため"this\0that\0"
)、空の文字列でも「バッファーの最初の文字」を持ちます。
上記のポインターのいずれかが与えられた場合:
char c = p[n]; // valid for n <= x.size()
// i.e. you can safely read the NUL at p[x.size()]
非const
ポインタp_writable_data
とfromの場合のみ&x[0]
:
p_writable_data[n] = c;
p_x0_rw[n] = c; // valid for n <= x.size() - 1
// i.e. don't overwrite the implementation maintained NUL
文字列内の他の場所でNULを書くことはないではない変更string
のをsize()
。string
には任意の数のNULを含めることができます- std::string
(C ++ 03でも同じ)による特別な処理は行われません。
ではC ++ 03、物事はかなり多くの(主な相違点は、複雑された強調表示しました):
x.data()
- NULで終了するために標準で必要とされなかっ
const char*
た文字列の内部バッファに戻ります(つまり、初期化されていない値やガベージ値が続き、偶発的にアクセスすると未定義の動作が発生します)。
['h', 'e', 'l', 'l', 'o']
x.size()
文字が読み安全である、すなわちx[0]
通じx[x.size() - 1]
- 空の文字列の場合、0を安全に追加できるNULL以外のポインターが保証されています(万歳!)。ただし、そのポインターを逆参照しないでください。
&x[0]
- 空の文字列の場合、これは未定義の動作をします(21.3.4)
- 例えば与えられた
f(const char* p, size_t n) { if (n == 0) return; ...whatever... }
あなたは呼び出すことはできませんf(&x[0], x.size());
ときx.empty()
だけ使用することを- f(x.data(), ...)
。
- それ以外の場合は、次のように
x.data()
:
- 非-の場合、
const
x
これは非const
char*
ポインターを生成します。文字列コンテンツを上書きできます
x.c_str()
- 値
const char*
のASCIIZ(NUL終了)表現に戻ります(つまり、['h'、 'e'、 'l'、 'l'、 'o'、 '\ 0'])。
- すべての実装がそうすることを選択した場合、いくつかの、C ++ 03標準を作成するために、文字列の実装に自由を許可するように言葉で表現されたが、明確なNULで終了するバッファを その場で潜在的に非NULから、で「公開」バッファ終了
x.data()
し、&x[0]
x.size()
+ 1文字は安全に読み取ることができます。
- 空の文字列(['\ 0'])でも安全が保証されています。
外部の法的指標にアクセスした結果
どちらの方法でポインターを取得しても、上記の説明で保証されている文字よりもポインターから離れた場所にあるメモリにアクセスしないでください。これを実行しようとすると、動作が未定義になり、読み取りの場合でもアプリケーションがクラッシュしてガベージが発生する可能性が非常に高くなり、さらに書き込みの場合は、ホールセールデータ、スタックの破損、セキュリティの脆弱性が発生します。
それらのポインターはいつ無効になりますか?
string
を変更しstring
たり、追加の容量を予約したりするメンバー関数を呼び出すと、上記のメソッドのいずれかによって事前に返されたポインター値はすべて無効になります。これらのメソッドを再度使用して、別のポインターを取得できます。(ルールはstring
s へのイテレータと同じです)。
スコープをx
離れた後、または以下でさらに変更された後でも、文字ポインターを有効にする方法も参照してください。
それで、どちらを使うのが良いですか?
C ++ 11以降では.c_str()
、ASCIIZデータおよび.data()
「バイナリ」データ(以下でさらに説明)に使用します。
C ++ 03では、.c_str()
それ.data()
が適切であることが確実でない限り使用し、空の文字列に対して安全であることを優先.data()
し&x[0]
ます。
... data()
適切なときに使用するのに十分なほどプログラムを理解するようにしてください。そうしないと、おそらく他の間違いをするでしょう...
によって保証されるASCII NUL '\ 0'文字.c_str()
は、関連する安全なデータの終わりを示すセンチネル値として多くの関数で使用されます。これは、sayのようなC ++のみの関数と、およびのfstream::fstream(const char* filename, ...)
ようなCで共有される関数の両方に適用されます。strchr()
printf()
.c_str()
返されるバッファーに関するC ++ 03のの保証がのスーパーセットである.data()
ことを考えると、いつでも安全に使用できますが.c_str()
、人々はそうしない場合があります。
- を使用し
.data()
て、データがASCIIZではない(むしろ、文字列を使用してデータのブロックを格納している(実際にはテキストではないこともあります))か、またはデータをこれを「バイナリ」データのブロックとして扱う別の関数。これは、他のプログラマのコード変更がデータを適切に処理し続けることを保証する上で重要な洞察になる可能性があります。
- C ++ 03のみ:
string
NULで終了するバッファーを準備するために、実装が追加のメモリ割り当てやデータコピーを行う必要がある可能性がわずかにあります
さらにヒントとして、関数のパラメーターに(const
)char*
が必要であるが取得を要求しないx.size()
場合、関数はおそらく ASCIIZ入力を必要とするため.c_str()
、適切な選択です(関数はテキストがどこで終了するかを知る必要があるため、そうでない場合別個のパラメーター。これは、長さ接頭辞または歩哨またはいくつかの固定された期待される長さのような規則にすぎません。
x
スコープを離れた後、またはさらに変更された後でも文字ポインターを有効にする方法
の内容をの外の新しいメモリ領域にコピーする必要があります。この外部バッファーは、別の変数や文字配列変数などの多くの場所にある可能性があります。有効期間は、スコープが異なる(名前空間、グローバル、静的、ヒープ、共有メモリ、メモリマップファイルなど)場合と異なる場合があります。 。string
x
x
string
x
からテキストをstd::string x
独立した文字配列にコピーするには:
// USING ANOTHER STRING - AUTO MEMORY MANAGEMENT, EXCEPTION SAFE
std::string old_x = x;
// - old_x will not be affected by subsequent modifications to x...
// - you can use `&old_x[0]` to get a writable char* to old_x's textual content
// - you can use resize() to reduce/expand the string
// - resizing isn't possible from within a function passed only the char* address
std::string old_x = x.c_str(); // old_x will terminate early if x embeds NUL
// Copies ASCIIZ data but could be less efficient as it needs to scan memory to
// find the NUL terminator indicating string length before allocating that amount
// of memory to copy into, or more efficient if it ends up allocating/copying a
// lot less content.
// Example, x == "ab\0cd" -> old_x == "ab".
// USING A VECTOR OF CHAR - AUTO, EXCEPTION SAFE, HINTS AT BINARY CONTENT, GUARANTEED CONTIGUOUS EVEN IN C++03
std::vector<char> old_x(x.data(), x.data() + x.size()); // without the NUL
std::vector<char> old_x(x.c_str(), x.c_str() + x.size() + 1); // with the NUL
// USING STACK WHERE MAXIMUM SIZE OF x IS KNOWN TO BE COMPILE-TIME CONSTANT "N"
// (a bit dangerous, as "known" things are sometimes wrong and often become wrong)
char y[N + 1];
strcpy(y, x.c_str());
// USING STACK WHERE UNEXPECTEDLY LONG x IS TRUNCATED (e.g. Hello\0->Hel\0)
char y[N + 1];
strncpy(y, x.c_str(), N); // copy at most N, zero-padding if shorter
y[N] = '\0'; // ensure NUL terminated
// USING THE STACK TO HANDLE x OF UNKNOWN (BUT SANE) LENGTH
char* y = alloca(x.size() + 1);
strcpy(y, x.c_str());
// USING THE STACK TO HANDLE x OF UNKNOWN LENGTH (NON-STANDARD GCC EXTENSION)
char y[x.size() + 1];
strcpy(y, x.c_str());
// USING new/delete HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = new char[x.size() + 1];
strcpy(y, x.c_str());
// or as a one-liner: char* y = strcpy(new char[x.size() + 1], x.c_str());
// use y...
delete[] y; // make sure no break, return, throw or branching bypasses this
// USING new/delete HEAP MEMORY, SMART POINTER DEALLOCATION, EXCEPTION SAFE
// see boost shared_array usage in Johannes Schaub's answer
// USING malloc/free HEAP MEMORY, MANUAL DEALLOC, NO INHERENT EXCEPTION SAFETY
char* y = strdup(x.c_str());
// use y...
free(y);
他の理由が欲しいするchar*
か、const char*
Aからの生成しますstring
だから、あなたの上に(取得する方法を見てきましたconst
)をchar*
、そしてどのように元のテキストに独立のコピーを作成するにはstring
、しかし、あなたは何をすることができませんそれで?例のランダムな散らばり...
- "C"コードにC ++
string
のテキストへのアクセスを許可します。printf("x is '%s'", x.c_str());
- コピー
x
あなたの関数の呼び出し側で指定されたバッファへのテキストを(例えばstrncpy(callers_buffer, callers_buffer_size, x.c_str())
)、または揮発性メモリデバイスのために使用されるI / O(例えばfor (const char* p = x.c_str(); *p; ++p) *p_device = *p;
)
x
ASCIIZテキスト(例strcat(other_buffer, x.c_str())
)をすでに含んでいる文字配列にテキストを追加します-バッファをオーバーランしないように注意してください(多くの状況で使用する必要があるかもしれませんstrncat
)
- 関数から、
const char*
またはchar*
関数から返します(おそらく歴史的な理由-クライアントが既存のAPIを使用している-またはC互換性のためにstd::string
、を返したくないがstring
、呼び出し元のためにのデータをどこかにコピーしたい)
string
そのポインターが指しているローカル変数がスコープを出た後、呼び出し元によって逆参照される可能性のあるポインターを返さないように注意してください
- 異なる
std::string
実装用にコンパイル/リンクされた共有オブジェクトを含む一部のプロジェクト(STLportやコンパイラネイティブなど)は、競合を回避するためにASCIIZとしてデータを渡すことがあります