C语言中如何通过值传递结构体的memcpy函数

3

我只是想将一个结构体复制到另一个结构体(按值而非按引用复制)。这是完全可运行的代码:

/* memcpy example */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define SIZE (80*sizeof(char))

typedef struct {
    char* name;
} person;

int main ()
{
  person p1;
  p1.name = (char*) malloc( SIZE );

  person p2;
  p2.name = (char*) malloc( SIZE );

  // set p1
  strcpy(p1.name, "John");

  // copy p1 > p2
  memcpy ( &p2, &p1, SIZE );

  printf ("p1.name: %s (%u)\n", p1.name, &p1.name );
  printf ("p2.name: %s (%u)\n", p2.name, &p2.name );

  // change p1 only
  printf("Changing p1.name\n");
  strcpy(p1.name, "ONLY p1.name Changed");

  // now, why did p2 change?
  printf ("p1.name: %s (%u)\n", p1.name, &p1.name );
  printf ("p2.name: %s (%u)\n", p2.name, &p2.name );

  free(p1.name);
  free(p2.name);

  return 0;
}

这里是一个示例 http://cpp.sh/57skb 这段代码输出了:
p1.name: John (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)
Changing p1.name
p1.name: ONLY p1.name Changed (0x791b3cdd6270)
p2.name: ONLY p1.name Changed (0x791b3cdd6280)

预期输出将会是:
p1.name: John (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)
Changing p1.name
p1.name: ONLY p1.name Changed (0x791b3cdd6270)
p2.name: John (0x791b3cdd6280)

问题:为什么p2会改变?

请注意,如果不使用结构体进行相同操作,则可以按预期工作:http://cpp.sh/6qevd


@WhozCraig 这里包含了代码。你不应该因为这个而投反对票,你的评论已经足够了。 - Skacc
谁说我给任何东西点了踩?我没有。我不会对问题进行负面评价。如果它们太糟糕/准备不足,值得被踩,我会选择投票关闭它们(但我在这里没有这样做)。谁给你的问题点了踩,请到别处寻找,因为那不是我。 - WhozCraig
@WhozCraig 我猜错了,抱歉。 - Skacc
3个回答

3
当您复制时,两个结构的name成员将具有相同的值,因此它们指向相同的内存位置。由于您没有正确打印指针值,因此您的代码没有显示出这一点。尝试使用以下代码来查看它们是否确实相同。
  printf ("p1.name: %s (%p)\n", p1.name, p1.name );
  printf ("p2.name: %s (%p)\n", p2.name, p2.name );

输出

p1.name: John (0x3ee8d60)
p2.name: John (0x3ee8d60)

p2在执行strcpy(p1.name, "ONLY p1.name Changed");后并没有改变。它仅仅是指向了这个新字符串。


2
如果你只是复制结构体,那么你覆盖的是指针本身,而不是指针所指向的内容。你可能想要做的是,不使用memcpy,而是这样做:
size_t bytes = strlen(p1.name)+1;
p2.name = realloc(p2.name, bytes);
if (p2.name != NULL) {
    memcpy(p2.name, p1.name, bytes);
}

这里,“bytes”是名称中字符数加上字符串结束符的数量,调用“realloc”更改p2.name的大小以匹配它。现在,保证有足够的空间,您可以将第一个名称复制到第二个名称中。
在这里使用realloc可能是低效的,因为它保留了我们不需要的p2.name的原始内容。另一种选择是先释放旧字符串,然后再为新字符串分配空间:
size_t bytes = strlen(p1.name)+1;
free(p2.name);
p2.name = malloc(bytes);
if (p2.name != NULL) {
    memcpy(p2.name, p1.name, bytes);
}

请注意,malloc和realloc都可能失败,如果您的程序内存不足,则会返回NULL,因此最好始终检查这一点。


1

你需要复制已分配的内存区域而不是结构体本身。

memcpy ( p2.name, p1.name, SIZE );

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接