C语言中使用char数组深度复制结构体(如何复制数组?)

tnkciper  于 2023-01-12  发布在  其他
关注(0)|答案(4)|浏览(179)

我的C程序中有以下结构

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

我想做一个这个结构体的深度拷贝。我已经设置了深度拷贝函数,但是我对如何深度拷贝字符串有点困惑。我听说有人用strcpy,也有人用strdup
在我的程序中,我希望深度复制的人的键和颜色在原始人被释放时不受影响。一旦设置,键和颜色就不能改变。对于我的目的,我应该使用strcpy还是strdup函数?

deyfvvtc

deyfvvtc1#

Post-K & R(即在标准C中)1你可以直接赋值。下面的函数只是为了让例子更清楚,你总是直接赋值:

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

详细说明:char数组是struct对象的一部分(真正的数组,而不仅仅是指针!),因此与对象一起分配和复制。
为了满足不信者;- )我在1570年的标准草案中四处挖掘:

    • 6.5.16赋值运算符**
    • 语义**

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

    • 6.5.16.1简单赋值**
    • 制约因素**

应满足以下条件之一:

  • [...]
  • 左操作数具有与右操作数的类型兼容的结构或联合类型的原子、限定或非限定版本;

[...]

    • 语义**

在 * 简单赋值 *(=)中,右操作数的值转换为赋值表达式的类型,并且替换左操作数指定的对象中存储的值。
1 The first edition of The C Programming Language,由贝尔实验室的Brian W. Kernighan和Dennis M. Ritchie编写,于1978年出版,是第一个C语言版本的非正式语言规范,通常被称为"K & R C",以该书的两位作者的名字命名(并作为与10年后指定的ANSI C的区别)。该书的第一版在第121页包含以下句子:
基本规则是,您可以对结构执行的唯一操作是用&获取其地址,并访问其成员之一。
特别是,您不能分配结构。(但他们继续"这些限制将在即将到来的版本中删除"。)
事实上,这是10年后通过的ANSI版本中为数不多的对语言的实质性(相对于语法)补充之一。Kernighan和Ritchie准备了一个随附的"ANSI C版"。这句话,这次在第129页,现在读作:
结构上唯一合法的操作是**将其作为一个单元进行复制和赋值,使用&获取其地址,并访问其成员。
他们详细说明:
复制和赋值包括向函数传递参数以及从函数返回值。
这种等价性在今天最新的C标准中仍然成立。
既然我们现在是在C
的根管里:下一个语句是一个绝对的
"Structures may not be compared."**有趣的是,他们添加了这句话--显然,内置比较在引入内置赋值之后出现了,但被拒绝了。在我看来,这从来没有一个好的理由:如果你可以按成员分配,为什么不也用这种方式比较呢?在很多情况下,这就很好了,而且手动比较很难维护。又花了30年的时间才在C++20中用spaceship operator使之成为可能,spaceship operator在(显式)默认时生成所有其他比较;实际上,它默认为成员间比较。

wr98u20j

wr98u20j2#

要对包含数组(不带任何指针)的结构执行深层复制,深层复制非常简单

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()是否成功)。

sigwle7e

sigwle7e3#

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

  • strdup()分配空间并返回一个指向字符串副本的指针,您还必须free()返回的指针。
  • strcpy()获取分配的空间并将字符串复制到其中。

在您的例子中,它似乎是strcpy(),因为您的结构的字段不是指针,所以您不能为它们分配一个指向已分配空间的指针,而这是strdup()返回的结果。
但是,正如this answer中所解释的,实际上您不需要这样做。

mtb9vblg

mtb9vblg4#

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

相关问题