1

次のコードでは、c ++で2D配列を作成しようとしていますが、このプログラムを実行すると失敗します。

#include <iostream>
#include <vector>
using namespace std;

int obtain_options(  char ** optionLine)
{
   vector< char*> options;
   options.push_back("abc");
   options.push_back("def");


   std::copy(options.begin(), options.end(), const_cast< char**>(optionLine));

   return options.size();
}

int main(int ac, char* av[])
{
    char** optionLine;
    int len;
    optionLine = new char* [2];
    for (int i= 0; i<2; i++)
    {
       optionLine[i] = new char [200];
    }
     obtain_options(optionLine);
    for (int i=0; i<2; i++)
    {
        cout<<optionLine[i]<<endl;
     }

    for (int i=0; i<2; i++)
        delete  [] (optionLine[i]);
    delete []optionLine;

   return 0;

} 

関数getate_options()のoptionLineへのメモリの割り当てに問題があることを理解しています。このようにgettain_options()を変更すると、次のように機能します。

int obtain_options(  char ** optionLine)
{
    vector< char*> options;
    char *t1 = new char [100];
    t1[0] = 'a';
    t1[1] = 'b';
    t1[2] = 'c';
    t1[3] = '/0';
   options.push_back(t1);
    char *t2 = new char [100];
    t2[0] = 'd';
    t2[1] = 'e';
    t2[2] = 'f';
    t2[3] = '/0';
   options.push_back(t2);


   std::copy(options.begin(), options.end(), const_cast< char**>(optionLine));

   return options.size();
}

私の質問は、gettain_options()を変更しない場合、2D配列optionLineを適切な方法で削除するにはどうすればよいかということです。

4

3 に答える 3

2

ベクターには文字ポインタのセットが含まれています。ただし、これらの文字列が指す実際のメモリは、期待どおりに連続していません。したがって、この呼び出しは期待どおりに機能しません。

std::copy(options.begin(), options.end(), const_cast< char**>(optionLine));

最悪の場合、あなたはこのようにすることができます、それはあなたが今ほとんど自分でしていることです。

for (int i= 0; i<2; i++)
{
     strcpy(optionLine[i],options[i]);
}

ただし、ポインタと割り当てを学習している場合を除いて、これらすべてのメモリ処理は避けてください。

C++でこのようにコーディングできる方法をご覧ください。

int obtain_options( vector<string>& anOptions_out)
{
    anOptions_out.push_back("abc");
    anOptions_out.push_back("def");

    return anOptions_out.size();
}

int main(int ac, char* av[])
{
    vector<string> anOptions;
    obtain_options( anOptions );
    for (int i=0; i<anOptions.size(); i++)
    {
        cout<< anOptions[i].c_str() <<endl;
    }

    return 0;
} 

自分での割り当て/割り当て解除はありません。

于 2012-07-02T16:53:09.520 に答える
1

投稿されたコードはを呼び出しませんobtain_optionsoptionsただし、その関数では、ローカルオブジェクト( )から引数が指す配列に文字ポインタをコピーしていることに気付きましたoptionLine。から戻ると、これらのポインタは無効になるため、これは問題になりますobtain_options

他の人が指摘しているように、上記は問題の誤診です。

呼び出した後、あなたのコードがこれを行うことがわかりましたobtain_options

for (int i=0; i<2; i++)
    delete  [] (optionLine[i]);

これは、とを指す静的ポインタで演算子を呼び出していることを意味しdeleteます。"abc""def"

「政治的正しさ」はさておき、私の最初のアドバイスはまだ機能していると思います。

char*に置き換えてstd::string、をに置き換えchar**てみてくださいvector<std::string>

于 2012-07-02T16:49:30.017 に答える
1

ここのほとんどの人は、質問に答えるのではなく、あなたが認識している問題に対して政治的に正しい解決策を提供することに関心を持っているので、ここに私の貢献があります:

文字列の内容を手動で割り当てられたベクトルにコピーするのではなく、割り当てたポインタを内部のポインタに置き換えます。vector< char*> options;

あなたがするとき:

char *a = "abc";

技術的には正しい使用方法ですが、静的に割り当てられたC文字列(定数)へのポインタを保持するconst charと言われています。あなたがするとき:a"abc"

options.push_back("abc");

このポインタをの中に置きます。そうすると、次のvectorようになります。

std::copy(options.begin(), options.end(), const_cast< char**>(optionLine));

optionsLineの元のポインタをのポインタに置き換えるだけですoptions。Dan Breslauが言ったこととは反対に、これらのポインターは静的であるため、つまりプログラムの全期間中に存在するため、関数からこれらのポインターを返すことに問題はありません。元のobatin_options関数を使用している間、これをメインとして簡単に行うことができます。

int main(int ac, char* av[])
{
   char** optionLine;
   int len;
   optionLine = new char* [2];
   obtain_options(optionLine)
   for (int i=0; i<2; i++)
     {
       cout<<optionLine[i]<<endl;
     }

   delete []optionLine;

   return 0;
}

optionLineのコンテンツは内部で失われるため、割り当てなかったことに注意してくださいobtain_options()。またobtain_options()、コンテンツが提供された配列に適合することを保証する方法がないため、非常に危険な関数です。size提供された配列のサイズで別のパラメーターを渡す方が安全optionLineです。その場合は、その制限を超えてコピーしないでください。

int obtain_options(  char ** optionLine, int size)
{
   vector< char*> options;
   options.push_back("abc");
   options.push_back("def");

   if(size > options.size())
      size = options.size();
   std::copy(options.begin(), options.begin() + size, const_cast< char**>(optionLine));

   return size;
}

または、PermanentGuestが提供する非常に安全なソリューションを使用する必要があります。

于 2012-07-02T17:14:24.970 に答える