【问题标题】:Deep copying structs with char arrays in C (How to copy the arrays?)在 C 中使用 char 数组深度复制结构(如何复制数组?)
【发布时间】:2015-05-01 15:10:14
【问题描述】:

我的 C 程序中有以下结构

struct person {
    char key[50];
    char color[20];
    int age;
};

我想制作这个结构的深层副本。我已经设置了深拷贝功能,但是我对如何深拷贝字符串有点困惑。我听说有人使用strcpy,其他人使用strdup

我希望在我的程序中,如果原始人被释放,深度复制的人的键和颜色不会受到影响。一旦设置,键和颜色不能改变。就我而言,我应该使用strcpy 还是strdup 函数?

【问题讨论】:

  • 由于发布的结构中没有 'char *' 字段,因此除了 memcpy(destStruct, srcStruct, sizeof destStruct);
  • 因为数组(不仅仅是指向它们的指针!)是结构的成员,所以浅拷贝就是深拷贝。没有间接性。您的结构的内存占用 > 70 字节,在堆栈上,在堆上,在任何你想要的地方。

标签: c struct deep-copy


【解决方案1】:

Post-K&R(即在标准 C 中)您可以分配它们。下面的函数只是为了让例子更清楚,你总是就地分配:

void deepCopyPerson(struct person *target, struct person *src)
{
    *target = *src;
}

详细说明:char 数组是结构对象的一部分(真正的数组,不仅仅是指针!),因此与对象一起分配和复制。

为了满足不相信的人 ;-) 我在标准草案 1570 中进行了挖掘:

6.5.16 赋值运算符

语义

赋值运算符将值存储在左操作数指定的对象中。 [后面是与此处无关的类型转换和排序注意事项。]

[...]

6.5.16.1 简单赋值

约束

应满足以下条件之一:

  • [...]

  • 左操作数 具有结构的原子、合格或不合格版本,或 union 类型与正确的类型兼容;

[...]

语义

简单赋值(=)中,右操作数的值被转换 赋值表达式的类型并替换存储的值 在左操作数指定的对象中。

【讨论】:

  • 这不会复制结构。对于复制结构,使用 memcpy() 而不是赋值
  • @user3629249 是什么让你这么想?我认为在 inet 标头的某个地方,他们使用技巧将 只是一个数组 (而不是其他任何东西)放在一个结构中,只是为了防止数组衰减并能够将其作为参数传递。
  • Peter Schneider 在这种情况下是正确的,user3629249,因为结构包含数组而不是指针。
【解决方案2】:

要对包含数组(没有任何指针)的结构执行深拷贝,深拷贝很简单

struct person x = {"Key", "Color", 42};   /*  initialise to something */
struct person y = x;

如果“字符串”是指针,这不起作用。然后需要分配新的字符串,然后使用 strcpy() 之类的函数来复制成员。

#include <stdlib.h>
#include <string.h>

struct pointer_person
{
    char *key;
    char *color;
    int age;
};

struct pointer_person deep_copy(struct pointer_person p)
{
     struct pointer_person retval;
     retval.key = malloc(strlen(p.key) + 1);
     strcpy(retval.key, p.key);
     retval.color = malloc(strlen(p.color) + 1);
     strcpy(retval.color, p.color);
     retval.age = p->age;
     return retval;
}

int main()
{
   struct pointer_person p;
   struct pointer_person pc;

   p.key = malloc(50);
   strcpy(p.key, "A key");
   p.color = malloc(20);
   strcpy(p.color, "A colour");
   p.key = 42;

   pc = deep_copy(p);

   /* do stuff with pc and c */

   free(p.key);
   free(p.color);
   free(pc.key);
   free(pc.color);
   return 0;
}

上面遗漏了一些错误检查(例如,在复制之前需要检查malloc() 是否成功)。

【讨论】:

  • 我认为struct person y = x; 是一个初始化,而不是一个赋值(这将与static struct person y = x; 相关)。 C++ 更清楚区分(复制构造函数与赋值运算符)。
  • @PeterA.Schneider - 我同意struct person y = x 是一个初始化,而不是一个赋值。但是,我不明白您发表评论的原因,因为我在这个答案中没有说明它是初始化还是赋值。
  • 这个问题不是关于复制结构本身,它只是关于char [] 成员。
  • @IharobAlAsimi - 好吧.....问题标题现在说的是,因为您刚刚修改它(在提出问题三年后)才这么说。我的回答也不受您的编辑影响。无论如何都没有实际意义-自从发布此问题以来,OP似乎一直没有在SO上活跃。我无法预测您的最新编辑是否会说服对您的答案持反对意见的三个投票者改变主意。
【解决方案3】:

如果你使用strcpy(),你必须自己分配内存。 strdup() 会为你做这件事。您可以使用其中任何一个来创建一个与原始内存块分开的新内存块,但自然strdup() 更简单,因为它不需要单独的malloc(strlen()) 调用。

【讨论】:

    【解决方案4】:

    strcpy()strdup() 之间存在差异。

    • strdup() 分配空间并返回指向字符串副本的指针,您还必须将返回的指针指向free()

    • strcpy() 占用分配的空间并将字符串复制到其中。

    在您的情况下,它似乎是strcpy(),因为您的结构的字段不是指针,因此您不能为它们分配指向分配空间的指针,这是strdup() 返回的。

    但是,正如this answer 中所述,您实际上不需要这样做。

    【讨论】:

    • memcpy() 的使用其实是浅拷贝。如果结构包含指针成员,则不会进行深度复制。
    • 内存复制给定的结构没有多大意义。该语言有一个现成的、内置的赋值工具,恰当地命名为赋值运算符=
    猜你喜欢
    • 1970-01-01
    • 2014-12-13
    • 2013-05-14
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 1970-01-01
    • 2013-08-20
    • 2010-10-08
    相关资源
    最近更新 更多