【问题标题】:How to deep copy an array of char * in C++如何在 C++ 中深度复制 char * 数组
【发布时间】:2017-11-01 07:39:31
【问题描述】:

我想执行 char** 的深层复制,但我不知道如何分配内存/复制此数据类型。这适用于包含 char** 的类中的复制构造函数。例如,假设我有这个代码:

char ** arr1 = new char*[20];
arr1[0] = (char*)"This is index 1";
arr1[1] = (char*)"This is index 2";
char ** arr2;

如何将 arr1 的内容深度复制到 arr2 中?任何帮助表示赞赏!

【问题讨论】:

  • 你拼错了std::vector<std::string>
  • @StoryTeller 哈哈,我希望。这是一个编程作业,老师希望所有字符串都存储为 char*,因此必须将字符串数组存储为 char* 数组。我认为不必要的复杂化,而不是我为自己做的方式,但我必须学习如何为这项任务做这件事。
  • 这是C课程吗?鉴于您的示例,无法判断 arr1 中有多少个字符串(除非它存储在某处的条目数)
  • @AdrianBernat:为了更明确一点,我们认为这是一个非常糟糕的编程任务。以这种方式教授 C++ 在 20 世纪可能是可以接受的,但在这个时代已经没有立足之地。即使您确实想教授底层操作,您也必须在 教授 C++ 基础知识之后这样做,而且这样做是正确的。您将char[] 包装在您自己的String 类中,然后构建自定义Vector<String>
  • 找一个更好的老师。

标签: c++ arrays char deep-copy


【解决方案1】:

这是一个编程作业,老师想要所有字符串 存储为 char*,...

您可以告诉老师 std::string 确实将字符串存储为 char*。如果他仍然不喜欢您使用std::string,您应该编写自己的包装器,因为使用裸char* 是您在编写C 时所做的,而不是在C++ 中。你应该写一个:

struct my_string {
    char* data;
    ... constructor, operator[], etc...
};

您基本上不需要编写比现在更多的代码,但您应该把它放在正确的位置(即隐藏在一个漂亮的界面后面)。当您考虑...时,您会立即看到它的好处...

...所以字符串数组必须存储为 char* 数组。

没有。一个字符串数组是std::array<my_string>(或者std::vector<my_string>,如果它应该是动态的)。如果你的老师坚持不使用std::vector,那么你应该像刚才对向量字符串所做的那样做同样的事情(即将所有脏指针和内存内容封装在一个地方)。

【讨论】:

    【解决方案2】:

    这看起来更像是一道 C 题,但这里有一个例子:

    char **AllocateAndDeepCopy(char **arr1, int arr1size) 
    {
        unsigned int    i;
        char            **arr2;
    
        /* Allocate string array */
        arr2 = new char*[arr1size];
    
        /* Iterate array elements */
        for (i=0; i<arr1size; i++) {
            /* Allocate string */
            arr2[i] = new char[strlen(arr1[i])+1];
    
            /* Copy contents */
            strcpy(arr2[i], arr1[i]);
        }   
    
        return arr2;
    }
    

    稍后你必须以这种方式释放arr2

    void DeallocateArr2(char **arr2, int size) 
    {
        for (int i=0; i<size; i++) {
            delete arr2[i];     
        }
    
        delete arr2;
    }
    

    【讨论】:

    • 我知道怎么做,因为我以前做过很多次深拷贝。然而,这确实激发了一个想法。我可能将数组的大小设置为可以传入的整数。然而,引发这个问题的难题是在没有传入数组大小的情况下进行深度复制。对于 char*,这一步是通过说 new char[strlen(to_copy) +1] 来完成,但是,我想不出为 char** 分配内存的等价物。是否可以在不将数组大小作为 int 传递给函数的情况下分配该内存?
    • 线索在于 char * 在内存中的布局方式与数组(即char **int * 等)的布局方式之间的区别,即 null-终结者.
    • 是的,您可以在数组arr1 的末尾使用NULL 元素,它可以用作其大小的指示符。然后你可以避免传递大小。
    【解决方案3】:

    对于 C++ 教育的糟糕状态,我只能摇头。我们有很长的路要走。但既然这显然是给定的,那么您能做的最好的事情是什么?

    要复制这样的 C 风格数据结构,您在复制时需要了解两件事。两者都不是由 C 样式数组固有地提供的,因此您必须明确地跟踪它们。

    • arr1容量:20。如果这不是编译时间常数,则必须存储它并传递它。由于您要实现一个复制 ctor,这意味着将容量存储在对象的非静态成员变量中。
    • arr1中使用的索引数2。和上面一样。或者确保所有未使用的索引都设置为nullptr

    现在你可以分配一个正确大小的arr2,然后分配+memcpy所有使用的索引。

    但是,无论如何,你的程序都会火上浇油,因为 arr1arr2 不能被同等对待,即使它们看起来相同。 arr1 使用的索引决不能是 deleted,因为它们包含指向字符文字的指针:它们从来不是 newd 并且存在于只读内存中。另一方面,您绝对必须delete arr2 的索引,因为它们 newd。

    如果任务真的需要这种对 const 的残酷无视,我会更进一步。我将介绍另一个成员变量,一个布尔数组,它跟踪 char 数组的哪些索引指向 char 字面量,哪些是动态分配的。在复制期间,您现在拥有 memcpy 或简单地设置指针的所有必要信息。疯狂的?当然,但整个任务是,这样疯狂至少是可见的,而不是隐藏在看似无辜的 C 风格演员后面。顺便说一句:那些应该是const_cast&lt;char*&gt; 以明确发生了什么。

    【讨论】:

      【解决方案4】:

      看看http://en.cppreference.com/w/cpp/algorithm/copy,深拷贝是由 *d_first++ = *first++;

      【讨论】:

      • 那是浅拷贝(它是一个指向数组的指针数组,所以是二维的,而一维循环必然是浅的)
      • 2D是艺术家的印象char *d_first=*arr2;char *first=*arr1;while (first!=last) *d_first++=*first++;很深。
      • 这是arr[0] 的一维副本,无法复制arr[1]
      猜你喜欢
      • 1970-01-01
      • 2013-05-14
      • 1970-01-01
      • 2017-04-15
      • 1970-01-01
      • 1970-01-01
      • 2013-12-03
      • 2012-04-15
      • 2013-07-21
      相关资源
      最近更新 更多