1

在下面的代码中,我尝试用 c++ 构建一个二维数组,但是当我运行这个程序时它失败了。

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

} 

我了解在函数 gain_options() 中为 optionLine 分配内存存在一些问题,如果我以这种方式更改 gain_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();
}

我的问题是,如果我不更改 get_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_options. 但是,我注意到在该函数中,您将字符指针从本地对象 ( options) 复制到参数指向的数组optionLine。这将是一个问题,因为一旦您从obtain_options.

正如其他人指出的那样,以上是对问题的误诊。

我现在看到您的代码在调用后执行此操作obtain_options

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

这意味着它delete在指向"abc"and的静态指针上调用运算符"def"

抛开“政治正确”不谈,我认为我最初的建议仍然有效:

尝试替换char*std::string,并替换char**vector<std::string>

于 2012-07-02T16:49:30.017 回答
1

由于这里的大多数人都关心为您所感知的问题提供政治上正确的解决方案,而不是回答问题,因此这是我的贡献:

您没有将字符串的内容复制到手动分配的向量中,而是将分配的指针替换为内部的指针vector< char*> options;

当你这样做时:

char *a = "abc";

虽然在技术上使用更正确const char,但据说a将保存指向静态分配的 C 字符串的指针"abc"(即常量)。当你这样做时:

options.push_back("abc");

你把这个指针放在里面vector,当你这样做时:

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

您只需将原始指针替换为 inoptionsLine中的指针即可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 回答