web-dev-qa-db-ja.com

std :: vector <std :: string> to char *配列

std::vector<std::string>を読み取るC関数の引数に使用する必要があるchar* fooがあります。 std::stringchar*に変換する seenhow があります。 C++の初心者として、ベクトルの各要素でこの変換を実行し、char*配列を生成する方法をまとめようとしています。

私はいくつかの密接に関連するSOの質問を見ましたが、ほとんどは別の方向に進み、std::vector<std::string>を作成する方法を示しているようです。

28

_std::transform_を次のように使用できます。

_std::transform(vs.begin(), vs.end(), std::back_inserter(vc), convert);  
_

convert()を次のように実装する必要があります。

_char *convert(const std::string & s)
{
   char *pc = new char[s.size()+1];
   std::strcpy(pc, s.c_str());
   return pc; 
}
_

テストコード:

_int main() {
       std::vector<std::string>  vs;
       vs.Push_back("std::string");
       vs.Push_back("std::vector<std::string>");
       vs.Push_back("char*");
       vs.Push_back("std::vector<char*>");
       std::vector<char*>  vc;

       std::transform(vs.begin(), vs.end(), std::back_inserter(vc), convert);   

       for ( size_t i = 0 ; i < vc.size() ; i++ )
            std::cout << vc[i] << std::endl;

       for ( size_t i = 0 ; i < vc.size() ; i++ )
            delete [] vc[i];
}
_

出力:

_std::string
std::vector<std::string>
char*
std::vector<char*>
_

オンラインデモ: http://ideone.com/U6QZ5

_&vc[0]_が必要な場合はいつでも_char**_を使用できます。

newを使用して各_std::string_(convert関数内)にメモリを割り当てるため、最後にメモリの割り当てを解除する必要があることに注意してください。これにより、ベクトルvs;を柔軟に変更できます。それに_Push_back_文字列を追加し、vsから既存の文字列を削除し、vc(つまり_vector<char*>_は引き続き有効です!

ただし、この柔軟性が必要ない場合は、次のconvert関数を使用できます。

_const char *convert(const std::string & s)
{
   return s.c_str();
}
_

そして、あなたは_std::vector<char*>_を_std::vector<const char*>_に変更しなければなりません。

変換後、新しい文字列を挿入するか、古い文字列を削除してvsを変更すると、vcのすべての_char*_が無効になる可能性があります。それが重要なポイントです。もう1つの重要な点は、コードで_delete vc[i]_を使用する必要がなくなったことです。

33
Nawaz

最善の方法は、ベクトルと同じサイズの_std::vector_を_const char*_に割り当てることです。次に、ベクトルの各要素をウォークして、c_str()を呼び出して文字列配列を取得し、配列の対応する要素を格納します。次に、このベクトルの最初の要素へのポインターを問題の関数に渡すことができます。

コードは次のようになります。

_std::vector<const char *> cStrArray;
cStrArray.reserve(origVector.size());
for(int index = 0; index < origVector.size(); ++index)
{
  cStrArray.Push_back(origVector[index].c_str());
}

//NO RESIZING OF origVector!!!!

SomeCFunction(&cStrArray[0], cStrArray.size());
_

cannotでは、_const char*_から_std::strings_ sをフェッチしてからC関数を呼び出すまでの間に文字列の元のベクトルのサイズを変更できることに注意してください。

10
Nicol Bolas

これは動作するはずです:

char ** arr = new char*[vec.size()];
for(size_t i = 0; i < vec.size(); i++){
    arr[i] = new char[vec[i].size() + 1];
    strcpy(arr[i], vec[i].c_str());
}

編集:

C関数がこの配列を何らかの方法で変更する場合、別の方法でサイズを取得する必要がある場合、vecの要素の数が正しいと仮定して、これらのデータ構造を解放します。

for(size_t i = 0; i < vec.size(); i++){
    delete [] arr[i];
}
delete [] arr;

もう一度編集:

C関数が文字列を変更しない場合、文字列をコピーする必要はないかもしれません。インターフェースがどのように見えるかについて詳しく説明できれば、より良いヘルプを提供できると確信しています。

7
GWW

std::stringの要素が連続して格納されることが保証されているC++ 0xソリューション:

std::vector<std::string> strings = /* from somewhere */;
int nterms = /* from somewhere */;

// using std::transform is a possibility depending on what you want
// to do with the result of the call
std::for_each(strings.begin(), string.end(), [nterms](std::string& s)
{ ModelInitialize(&s[0], nterms); }

関数が引数をnullで終了する場合、呼び出し後(s.begin(), s.end())は意味がないかもしれません。それを修正するために後処理できます:

s = std::string(s.begin(), std::find(s.begin(), s.end(), '\0'));

各文字列をchar[]に個別にコピーする、より精巧なバージョン:

typedef std::unique_ptr<char[]> pointer;
std::vector<pointer> args;
std::transform(strings.begin(), strings.end()
               , std::back_inserter(args)
               , [](std::string const& s) -> pointer
{
    pointer p(new char[s.size()]);
    std::copy(s.begin(), s.end(), &p[0]);
    return p;
});

std::for_each(args.begin(), args.end(), [nterms](pointer& p)
{ ModelInitialize(p.get(), nterms); });
0
Luc Danton