为什么以这种方式删除2D数组失败(C ++)?

时间:2012-07-02 16:43:02

标签: c++

在下面的代码中,我尝试用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;

} 

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

我的问题是如果我不更改obtain_options(),我怎么能以正确的方式删除2D数组optionLine。

3 个答案:

答案 0 :(得分: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;
} 

自己没有分配/解除分配。

答案 1 :(得分:1)

您发布的代码不会调用obtain_options。但是,我注意到在该函数中,您将字符指针从本地对象(options)复制到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>

答案 2 :(得分: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));

您只需使用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提供的安全解决方案。