1011

をまたはに変換するstd::stringにはどうすればよいですか?char*const char*

4

10 に答える 10

1207

std::string必要な関数に aを渡したいだけの場合は、const char*使用できます

std::string str;
const char * c = str.c_str();

のような書き込み可能なコピーを取得したい場合は、次のようchar *にします。

std::string str;
char * writable = new char[str.size() + 1];
std::copy(str.begin(), str.end(), writable);
writable[str.size()] = '\0'; // don't forget the terminating 0

// don't forget to free the string after finished using it
delete[] writable;

編集:上記は例外セーフではないことに注意してください。new呼び出しと呼び出しの間に何かがdeleteスローされると、何も自動的に呼び出されないため、メモリリークが発生deleteします。これをすぐに解決する方法は 2 つあります。

boost::scoped_array

boost::scoped_array範囲外になると、メモリが削除されます。

std::string str;
boost::scoped_array<char> writable(new char[str.size() + 1]);
std::copy(str.begin(), str.end(), writable.get());
writable[str.size()] = '\0'; // don't forget the terminating 0

// get the char* using writable.get()

// memory is automatically freed if the smart pointer goes 
// out of scope

std::vector

これは標準的な方法です (外部ライブラリは必要ありません)。std::vectorメモリを完全に管理する を使用します。

std::string str;
std::vector<char> writable(str.begin(), str.end());
writable.push_back('\0');

// get the char* using &writable[0] or &*writable.begin()
于 2008-12-07T19:35:43.763 に答える
216

言うなれば...

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...

上記のポインターはすべて同じ値(バッファー内の最初の文字のアドレス) を保持します。std::string("this\0that", 9)C++ 11 は、明示的に割り当てられた文字列コンテンツの後に余分な NUL/0 ターミネータ文字を常に保持することを保証するため (たとえば、 を保持するバッファを持ちます) 、空の文字列にも「バッファ内の最初の文字」があり"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 を書き込んでも、 's'は変更されませ。には任意の数の NUL を含めることができます。特別な処理は行われません(C++03 と同じ)。stringsize()stringstd::string

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)
      • たとえば、 whenf(const char* p, size_t n) { if (n == 0) return; ...whatever... }を呼び出してはならない場合は、を使用してください。f(&x[0], x.size());x.empty()f(x.data(), ...)
    • それ以外の場合は、次のx.data()とおりです。
      • non- の場合、const xこれは non- const char*pointer を生成します。文字列の内容を上書きできます
  • x.c_str()

    • const char*値の ASCIIZ (NUL 終了) 表現 (つまり、['h', 'e', 'l', 'l', 'o', '\0']) に戻ります。
    • そうすることを選択した実装はほとんどありませんが、C++03 標準は、文字列の実装 x.data()および&x[0]
    • x.size()+ 1 文字は安全に読めます。
    • 空の文字列 (['\0']) に対しても安全であることが保証されています。

外部の法定インデックスにアクセスした場合の結果

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

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

stringを変更するか、さらに容量を予約するメンバー関数を呼び出すstringと、上記のメソッドのいずれかによって事前に返されたポインター値はすべて無効になります。これらのメソッドを再度使用して、別のポインターを取得できます。(規則は s への反復子の場合と同じですstring)。

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

では、どちらを使うのが良いでしょうか?

C++11 からは.c_str()、ASCIIZ データと.data()「バイナリ」データ (以下でさらに説明) に使用します。

C++03 では、それが適切で.c_str()あることが確実でない限り使用し、空の文字列に対して安全であるため優先します.....data().data()&x[0]

...必要に応じて使用できるように、プログラムを十分に理解するように努めてください。そうしdata()ないと、他の間違いを犯す可能性があります...

によって保証される ASCII NUL '\0' 文字.c_str()は、関連する安全なアクセス データの終わりを示す番兵値として多くの関数で使用されます。これは、 say などの C++ 専用関数と、 、 、 などの C と共有される関数の両方に適用されfstream::fstream(const char* filename, ...)ます。strchr()printf()

返されたバッファに関するC++03 の.c_str()保証が のスーパーセットである.data()ことを考えると、いつでも安全に を使用できますが、次の.c_str()理由で使用できない場合があります。

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

さらなるヒントとして、関数のパラメータが ( const)を必要とするが、char*を取得することを主張しないx.size()場合、関数はおそらくASCIIZ 入力を必要とするため.c_str()、良い選択です (関数は、テキストがどこで終了するかを何らかの方法で知る必要があるため、そうでない場合別のパラメーターは、長さの接頭辞やセンチネル、または固定の期待される長さなどの規則のみにすることができます)。

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

の内容を の外の新しいメモリ領域にコピーする必要があります。この外部バッファーは、別の変数や文字配列変数などの多くの場所にある可能性があり、異なるスコープ (名前空間、グローバル、静的、ヒープ、共有メモリ、メモリ マップ ファイルなど) にあるため、有効期間が異なる場合とない場合があります。 .string xxstringx

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*から生成されたが必要なその他の理由string

const上記では、 ( )を取得するchar*方法と、元のテキストから独立したテキストのコピーを作成する方法を見てきましたが、それでstring何ができるでしょか? 例のランダムな散らばり...

  • string次のように、「C」コードに C++のテキストへのアクセスを許可します。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;)にコピーします。
  • xASCIIZ テキストを既に含む文字配列に のテキストを追加します (例: strcat(other_buffer, x.c_str())) - バッファをオーバーランしないように注意してください (多くの場合、 を使用する必要がある場合がありますstrncat) 。
  • const char*関数からまたはを返しchar*ます (おそらく歴史的な理由 - クライアントが既存の API を使用している - または C との互換性のために、 を返したくないが、呼び出し元のために のデータをどこか std::stringにコピーしたい)string
    • stringポインターが指すローカル変数がスコープを離れた後、呼び出し元によって逆参照される可能性のあるポインターを返さないように注意してください。
    • std::string異なる実装 (STLport やコンパイラ ネイティブなど)用にコンパイル/リンクされた共有オブジェクトを含む一部のプロジェクトでは、競合を避けるためにデータを ASCIIZ として渡す場合があります。
于 2010-11-11T09:21:35.420 に答える
37

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

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

C++11 までは、すべての文字が同じ連続したバッファーの一部であるという保証はありませんでしたが、実際には、既知の実装はすべてstd::stringそのように機能していました。「&s[0]」は std::string 内の連続した文字を指していますか?を参照してください。.

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

于 2008-12-07T19:31:50.387 に答える
22

C++17

C++17 (今後の標準) では、テンプレートの概要が変更され、次basic_stringの非 const オーバーロードが追加されdata()ます。

charT* data() noexcept;

戻り値: [0,size()] 内の各 i に対して p + i == &operator となるポインター p。


CharT const *からstd::basic_string<CharT>

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

CharT *からstd::basic_string<CharT>

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

C++11

CharT const *からstd::basic_string<CharT>

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

CharT *からstd::basic_string<CharT>

C++11 以降、標準では次のように規定されています。

  1. オブジェクト内の文字のようなオブジェクトは、basic_string連続して格納されます。つまり、任意のbasic_stringオブジェクトsについて、同一性はそのような&*(s.begin() + n) == &*s.begin() + nすべての値に対して保持されます。n0 <= n < s.size()

  1. const_reference operator[](size_type pos) const;
    reference operator[](size_type pos);

    戻り値: *(begin() + pos)if 、それ以外の場合は valuepos < size()の型のオブジェクトへの参照。参照値は変更されません。CharTCharT()


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

    p + i == &operator[](i)戻り値: for each iinのようなポインター p [0,size()]

const 以外の文字ポインターを取得する方法はいくつかあります。

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

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

プロ

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

短所

  • Final'\0'は変更されません/必ずしも非定数メモリの一部ではありません。

2.使用std::vector<CharT>

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

プロ

  • 単純
  • 自動メモリ処理
  • 動的

短所

  • 文字列のコピーが必要

3.コンパイル時定数 (および十分に小さい) のstd::array<CharT, N>場合に使用します。N

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

プロ

  • 単純
  • スタックメモリの扱い

短所

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

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

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.手動処理による生メモリの割り当て

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

プロ

  • 最大の「コントロール」

コン

  • 文字列のコピーが必要
  • エラーに対する最大の責任/感受性
  • 複雑
于 2016-01-12T15:53:11.970 に答える
10

これを見てください:

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

ただし、これは を返すことに注意してくださいconst char *

の場合、char *を使用して別の配列strcpyにコピーします。char

于 2013-05-12T08:18:16.850 に答える
10

入力として取得する多くの関数を備えた API を使用していchar*ます。

この種の問題に直面する小さなクラスを作成し、RAIIイディオムを実装しました。

class DeepString
{
        DeepString(const DeepString& other);
        DeepString& operator=(const DeepString& other);
        char* internal_; 
    
    public:
        explicit DeepString( const string& toCopy): 
            internal_(new char[toCopy.size()+1]) 
        {
            strcpy(internal_,toCopy.c_str());
        }
        ~DeepString() { delete[] internal_; }
        char* str() const { return internal_; }
        const char* c_str()  const { return internal_; }
};

そして、次のように使用できます。

void aFunctionAPI(char* input);

//  other stuff

aFunctionAPI("Foo"); //this call is not safe. if the function modified the 
                     //literal string the program will crash
std::string myFoo("Foo");
aFunctionAPI(myFoo.c_str()); //this is not compiling
aFunctionAPI(const_cast<char*>(myFoo.c_str())); //this is not safe std::string 
                                                //implement reference counting and 
                                                //it may change the value of other
                                                //strings as well.
DeepString myDeepFoo(myFoo);
aFunctionAPI(myFoo.str()); //this is fine

既存の文字列DeepStringの深くて一意のコピー (コピー不可) を作成しているため、このクラスを呼び出しました。DeepString

于 2011-03-29T13:32:16.967 に答える
9
char* result = strcpy((char*)malloc(str.length()+1), str.c_str());
于 2014-07-12T12:06:36.660 に答える