c++ - 違い - string char 変換 java




std:: stringをconst char*またはchar*に変換する方法は? (6)

C ++ 17

C ++ 17 (今後の標準)は、 basic_stringテンプレートの概要を変更し、 data()非constオーバーロードを追加しdata()

charT* data() noexcept;

戻り値:[0、size()]の各iについて、p + i ==&演算子となるようなポインタp。

CharT const * from std::basic_string<CharT>

std::string const cstr = { "..." };
char const * p = cstr.data(); // or .c_str()

CharT * from std::basic_string<CharT>

std::string str = { "..." };
char * p = str.data();

C ++ 11

CharT const * from std::basic_string<CharT>

std::string str = { "..." };
str.c_str();

CharT * from std::basic_string<CharT>

C ++ 11以降、標準では次のように述べています。

  1. basic_stringオブジェクト内のchar-likeオブジェクトは、連続して格納されます。 つまり、任意のbasic_stringオブジェクトs&*(s.begin() + n) == &*s.begin() + nは、 n 0 <= n < s.size() nすべての値に対して0 <= n < s.size()
  1. const_reference operator[](size_type pos) const;
    reference operator[](size_type pos);

    戻り値: pos < size() *(begin() + pos)場合は*(begin() + pos) 、そうでない場合はCharT()型のオブジェクトへの参照。 参照される値は変更されないものとする。

  1. const charT* c_str() const noexcept;
    const charT* data() const noexcept;

    戻り値: [0,size()]iについてp + i == &operator[](i)となるようなポインタp。

非const文字ポインタを得るためには、可能な方法があります。

1. C ++ 11の連続したストレージを使用する

std::string foo{"text"};
auto p = &*foo.begin();

プロ

  • シンプルで短い
  • 高速(コピーを伴わない方法のみ)

短所

  • 最終的な'\0'は変更しないでください。非constメモリの一部である必要はありません。

2. std::vector<CharT>使用します。

std::string foo{"text"};
std::vector<char> fcv(foo.data(), foo.data()+foo.size()+1u);
auto p = fcv.data();

プロ

  • シンプル
  • 自動メモリ処理
  • 動的

短所

  • 文字列のコピーが必要です

3. Nがコンパイル時定数(かつ十分に小さい)であればstd::array<CharT, N>

std::string foo{"text"};
std::array<char, 5u> fca;
std::copy(foo.data(), foo.data()+foo.size()+1u, fca.begin());

プロ

  • シンプル
  • スタックメモリの処理

短所

  • 静的
  • 文字列のコピーが必要です

4.自動ストレージ削除によるRAWメモリ割り当て

std::string foo{ "text" };
auto p = std::make_unique<char[]>(foo.size()+1u);
std::copy(foo.data(), foo.data() + foo.size() + 1u, &p[0]);

プロ

  • メモリ占有量が少ない
  • 自動削除
  • シンプル

短所

  • 文字列のコピーが必要です
  • 静的(動的な使用にはさらに多くのコードが必要)
  • ベクトルまたは配列より少ない機能

5.手作業でのRAWメモリ割り当て

std::string foo{ "text" };
char * p = nullptr;
try
{
  p = new char[foo.size() + 1u];
  std::copy(foo.data(), foo.data() + foo.size() + 1u, p);
  // handle stuff with p
  delete[] p;
}
catch (...)
{
  if (p) { delete[] p; }
  throw;
}

プロ

  • 最大 'コントロール'

コン

  • 文字列のコピーが必要です
  • エラーの最大責任/感受性
  • コンプレックス

どのようにstd::stringchar*またはconst char*に変換できますか?


const char *.c_str()メソッドを使用します。

あなたは&mystring[0]を使ってchar *ポインタを得ることができますが、いくつかの問題があります。必ずゼロ終了文字列を得る必要はなく、文字列のサイズを変更することはできません。 特に、文字列の最後を超えて文字を追加しないように注意する必要があります。そうしないと、バッファオーバーラン(およびクラッシュする可能性があります)が発生します。

実際には、 std::stringすべての既知の実装はとにかくそのように働いていたが、C ++ 11まではすべての文字が同じ連続バッファの一部であるという保証はなかった。 see "&s [0]"はstd :: stringの連続した文字を指していますか?

多くのstringメンバ関数は、内部バッファを再割り当てし、保存した可能性のあるポインタを無効にすることに注意してください。 すぐに使用して廃棄することをお勧めします。


これを試して

std::string s(reinterpret_cast<const char *>(Data), Size);

ちょうどこれを見てください:

string str1("");
const char * str2 = str1.c_str();

ただし、これはconst char *を返すことに注意してください。char char *場合は、 strcpyを使用して別のchar配列にコピーします。


言うまでもなく...

std::string x = "hello";

`string`から` char * `または` const char * `を得る

xが有効範囲内にあり、さらに変更されていないx有効な文字ポインタを取得する方法

C ++ 11は物事を単純化します。 次のすべてが同じ内部文字列バッファへのアクセスを与えます:

const char* p_c_str = x.c_str();
const char* p_data  = x.data();
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()]

&x[0]からの非constポインタの場合のみ:

p_x0_rw[n] = c;  // valid for n <= x.size() - 1
                 // i.e. don't overwrite the implementation maintained NUL

文字列内の他の場所にNULを書き込んでも、文字列のsize() 変更されませstringは任意の数のNULを含むことができます - std::string (C ++ 03と同じ)によって特別な扱いが与えられません。

C ++ 03では、事態はかなり複雑になりました(重要な違いが強調されました )。

  • x.data()

    • は、文字列の内部バッファにconst char*を返します。 このバッファは、NULで終わるために標準によって必要とされなかった (つまり、 ['h', 'e', 'l', 'l', 'o']後に未初期化または不明確なアクセスを伴い、 未定義の挙動を有する)。
      • x[0]からx[x.size() - 1] x.size()文字は安全ですx[x.size() - 1]
      • 空文字列に対しては、0が安全に追加できる(NULLでない)ポインタが保証されていますが、そのポインタを逆参照しないでください。
  • &x[0]

    • 空の文字列の場合、これは未定義の動作をします (21.3.4)
      • 例えば与えられたf(const char* p, size_t n) { if (n == 0) return; ...whatever... } f(const char* p, size_t n) { if (n == 0) return; ...whatever... } f(&x[0], x.size());呼び出さないでくださいf(&x[0], x.size()); x.empty() - f(x.data(), ...)使うだけf(x.data(), ...)
    • そうでなければ、 x.data()が、
      • const x 、非const char*ポインタが生成されます。 文字列の内容を上書きすることができます
  • x.c_str()

    • const char*を値のASCIIZ(NUL終端)表現(つまり、 ''、 '、'、 '、'、 '、'、 '0')に戻します。
    • いずれの実装もそうすることを選択したとしても、C ++ 03標準は、文字列の実装が、 NULで終端された可能性のあるバッファ を、 x.data()&x[0]
    • x.size() + 1文字は安全です。
    • 空の文字列(['\ 0'])でも安全を保証します。

法外なインデックスへのアクセスの結果

どのような方法でポインタを取得しても、上記の説明で保証されている文字よりポインタからさらに離れてメモリにアクセスしないでください。 そうしようとすると未定義の動作が起こり、アプリケーションのクラッシュやガベージ・リカバリ、さらにはデータの卸売り、スタックの破損や書き込みに対するセキュリティの脆弱性が発生する可能性が非常に高くなります。

これらのポインタはいつ無効になりますか?

stringを変更したり、余分な容量を予約するstringメンバ関数を呼び出すと、上記のいずれかの方法で事前に返されたポインタ値は無効になります。 これらのメソッドを再び使用して、別のポインタを取得することができます。 (ルールはイテレータのstringと同じです)。

またxがスコープを離した後であっても、以下でさらに変更された後でも、文字ポインタを有効にする方法を参照してください。

それで、どちらを使うのが良いですか?

C ++ 11では、ASCIIZデータの場合は.data() 、バイナリデータの場合は.c_str()を使用します(詳細は後述)。

C ++ 03では、 .data()が適切であるか.data()かを.data() 、空の文字列で安全であるため&x[0]より.data()を優先さ.data()ない限り、 .c_str()使用して.c_str()

...適切なときにdata()を使用data()十分なほどプログラムを理解しようとすると、おそらく他の間違いをするでしょう...

.c_str()によって保証されたASCII NUL '\ 0'文字は、多くの関数で、関連する安全なデータの終わりを示すセンチネル値として使用されます。 これは、 fstream::fstream(const char* filename, ...)strchr()printf()ようなCとの共有関数のようなC ++のみの関数に適用されfstream::fstream(const char* filename, ...)

返されたバッファに関するC ++ 03の.c_str()の保証が.data()のスーパーセットである場合、安全に.c_str()使用できますが、

  • .data()を使用すると、データがASCIIZでないことをソースコードで読み取る他のプログラマーと通信します(むしろ、文字列を使ってデータブロック(実際はテキストでもない)を格納しています)それを「バイナリ」データのブロックとして扱う別の関数に渡します。 これは、他のプログラマーのコード変更がデータを適切に処理し続けることを保証する上で重要な洞察になります。
  • C ++ 03のみ:NUL終了バッファを準備するために、 string実装で追加のメモリ割り当てやデータコピーが必要になる可能性はわずかです

さらにヒントとして、関数のパラメータが( constchar*必要とするがx.size()取得を主張していない場合、関数はおそらく ASCIIZ入力を必要とするため、 .c_str()は良い選択です何らかの理由でテキストが終了する場所を知るために、別のパラメータでない場合は、length-prefixやsentinelや固定長のような慣習に過ぎません)。

xがスコープを出た後、またはさらに変更された後でも文字ポインタを有効にする方法

string x内容をx以外の新しいメモリ領域にコピーする必要があります。 この外部バッファは、別のstringや文字配列変数など、多くの場所に存在する可能性があります。異なるスコープ(たとえば、名前空間、グローバル、スタティック、ヒープ、共有メモリ、メモリマップなど)ファイル)。

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);

stringから生成されるchar*またはconst char*を必要とするその他の理由

だから、あなたは( constchar*を取得する方法を見てきましたし、元のstringから独立したテキストのコピーを作る方法はありますが、それで何ができますか? 例をランダムに散らばっています...

  • printf("x is '%s'", x.c_str());ように、C ++ stringのテキストに "C"コードでアクセスしprintf("x is '%s'", x.c_str());
  • デバイスのI / Oに使用される揮発性メモリ(例えばfor (const char* p = x.c_str(); *p; ++p) *p_device = *p; strncpy(callers_buffer, callers_buffer_size, x.c_str())関数の呼び出し側で指定されたバッファにxのテキストをコピーします(例: strncpy(callers_buffer, callers_buffer_size, x.c_str()) for (const char* p = x.c_str(); *p; ++p) *p_device = *p;
  • バッファにオーバーランしないように注意してください(多くの場合、 strncat必要があるかもしれません)。たとえば、 strcat(other_buffer, x.c_str()) ASCIIZテキストを含む文字配列にxのテキストを追加します。
  • 関数からconst char*またはchar*を返す(歴史的な理由で - クライアントが既存のAPIを使用している - あるいはC互換性のためにstd::stringを返すことは望まないが、 stringのデータをコピーしたい発信者のどこかに)
    • そのポインタが指し示すローカルstring変数がスコープを離れると、呼び出し元によって参照解除される可能性のあるポインタを返さないように注意してください
    • std::string実装(STLportやcompiler-nativeなど)ごとにコンパイル/リンクされた共有オブジェクトを持つプロジェクトでは、競合を避けるためにASCIIZとしてデータを渡すことがあります

char* result = strcpy((char*)malloc(str.length()+1), str.c_str());






const