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


894

どのようにして変換することができますstd::stringchar*const char*


2
代わりに:char * writable = new char [str.size()+ 1]; char writable [str.size()+ 1]を使用できます。その後、書き込み可能または例外処理の削除について心配する必要はありません。

7
コンパイル時にサイズがわからない場合はstr.size()を使用できません。また、固定サイズの値が大きい場合は、スタックがオーバーフローする可能性があります。
ポール

1
char *結果= strcpy((char *)malloc(str.length()+ 1)、str.c_str());
cegprakash 14

7
@cegprakash strcpymalloc本当にC ++の方法ではありません。
ボイシー2014

4
いいえ、ただしchar* dest = new char[str.length() + 1]; std::copy(str.begin(), str.end(), dest)より慣用的なC ++になります。strcpy()そして、malloc()間違っているかは問題ではありませんが、コードの同じブロックにC ++同等とC ++の文字列とCライブラリの機能を使用するために一貫性のないようです。
ボイシー2014

回答:


1056

std::stringを必要な関数に渡すだけの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()

41
char * result = strdup(str.c_str());を使用するだけです。
Jasper Bekkers 2008

63
可能ですが、strdupはACまたはC ++の標準関数ではありません。それはposixからのものです:)
Johannes Schaub-litb

14
私がおそらく一般的に好むのはstd :: vector <char> writable(str.begin()、str.end());です。writable.push_back( '\ 0'); char * c =&writable [0];
ヨハネスシャウブ-litb 2008

17
std :: copyは、これを行うC ++の方法であり、文字列ポインタを取得する必要はありません。C関数はできるだけ使用しないようにしています。
Johannes Schaub-litb 2008

16
C ++ 17以降std::string::data()CharT*ではなくを返すようになりましたconst CharT*。この回答を更新することをお勧めします:)
Rakete1111

192

言うと...

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たり、追加の容量を予約したりするメンバー関数を呼び出すと、上記のメソッドのいずれかによって事前に返されたポインター値はすべて無効になります。これらのメソッドを再度使用して、別のポインターを取得できます。(ルールはstrings へのイテレータと同じです)。

スコープ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のみ:stringNULで終了するバッファーを準備するために、実装が追加のメモリ割り当てやデータコピーを行う必要がある可能性がわずかにあります

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

4
良いですね。char *(非const)が必要なもう1つの理由は、MPIブロードキャストで動作するためです。前後にコピーする必要がない場合は、見栄えが良くなります。私は文字列にchar * constゲッターを個人的に提供したでしょう。constポインタですが、編集可能な文字列です。const char *から文字列への暗黙の変換が混乱している可能性がありますが
bartgol 2014年

33

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

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

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

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


1
data()はconst char * :)を返すことに注意してください。これは&str [0]の意味です。これは連続しているが、ヌルで終了する必要のない文字列を返します。
Johannes Schaub-litb 2008

1
@ litb、Argh!それは私が簡単な答えを立てようとするために私が得るものです。私は過去にあなたの解決策を使ったことがあります。なぜそれが最初に思い浮かばなかったのかわかりません。回答を編集しました。
Mark Ransom

2
技術的には、std :: stringストレージはC ++ 0xでのみ隣接します。
MSalters 2008

1
@MSalters、ありがとう-知らなかった。しかし、そうではない実装を見つけるのは難しいでしょう。
Mark Ransom

2
char *結果= strcpy(malloc(str.length()+ 1)、str.c_str());
cegprakash 14

21

C ++ 17

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

charT* data() noexcept;

戻り値:[0、size()]の各iに対してp + i ==&演算子となるようなポインター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. オブジェクト内のcharのようなオブジェクトはbasic_string連続して格納されます。つまり、任意のbasic_stringオブジェクトsについて、アイデンティティ&*(s.begin() + n) == &*s.begin() + nnそのようなすべての値に対して保持されるものとします0 <= n < s.size()

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

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


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

    戻り値:p + i == &operator[](i)iinのポインタp [0,size()]

const以外の文字ポインタを取得するために、いくつかの可能な方法があります。

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

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

プロ

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

短所

  • final '\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. std::array<CharT, N>if 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;
}

プロ

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

コン

  • 文字列のコピーが必要
  • エラーに対する最大の責任/感受性
  • 繁雑

9

多くの関数が入力として取得する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はコピーできません)を作成しているので、クラスを呼び出しました。


3
この命名規則は避けます。c_str()によって使用されるのstdは「const string」ではなく「C-string」の省略形であり、str()常にstd::basic_stringnot char*(たとえばstd::stringstream::str())を返します
bcrist

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

1
見た目は良いですが、本当に理解するのは難しいです...シンプルは最高のIMOです
Naeem A. Malik

4
strcpy()、malloc()、length()およびc_str()は基本的な関数であり、これには難しいことは何もありません。メモリを割り当ててコピーするだけです。
cegprakash 2014

5
はい、機能は基本ですが、スパゲッティのボウルまたはライナーのフランケンシュタインのモンスターのように見えるようにねじって曲げました:)
Naeem A. Malik 14

4
はい、機能は基本的なものですが...プログラミング言語を使い始めたときのことを覚えていましたか?説明が必要な行がいくつかあります。これは、たとえば初心者が、たとえばこの回答とは異なる、またはそれよりも優れている理由を知るのに役立ちます :)
Hastur

2
@cegprakash:malloc()があるときはいつでも、free()も必要です。それ以外の場合、コードはメモリをリークし、回答の解決策もリークします。必要な割り当て解除をほのめかすことなくメモリを割り当てることは、そのような質問には不適切です。
Striezel

7

これを見てください:

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

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

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


23
こんにちは。あなたが投稿した内容は、5年前の質問に対する他の回答で、すでに何度も述べられています。古い質問に答えることは問題ありませんが、新しい情報を追加する場合のみです。そうでなければ、それは単なるノイズです。
マット2013年

7
個人的に、私はその単純さに感謝します。
TankorSmash 2014

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.