将结构体指针转换为char*并复制

3
我有以下代码:
struct Info { int age; char name[5]; }
char buffer[20];
Info i;
i.age = 10;
sprintf(i.name, "Case");
strncpy(buffer+5, (char*)&i, sizeof(Info));

现在我想恢复记录。
Info j;
strncpy((char*)&j, buffer+5, sizeof(Info));
printf("%d %s", j.age, j.name);

然而,这段代码打印出来的姓名为空字符串。我不确定我的操作是否有误。

2
strncpy函数会在遇到空字符\0时停止复制。将结构体强制转换为char*类型后,使用strncpy函数是无效的。你可以使用memcpy函数代替。 - Chad
为什么是5?应该是sizeof(Info) - Andrey
1
为什么buffer的大小是10个字节?为什么你从buffer + 5开始?为什么只复制5个字节? - ecatmur
4
这非常非常糟糕。 - Puppy
1
“这仍将是结构体的一部分,因为编译器将为i.name占用8个字节,对此你是依赖的吗?当“不要走”标志刚亮起来时,你是否也开始穿过马路而不看红灯,因为“红灯还会亮一小段时间…” 对我来说两者同样合理。” - Mats Petersson
显示剩余5条评论
4个回答

6

您的复制机制存在两个问题:

  1. 您假设 sizeof(Info) 的值为5,但这绝对不是正确的。
  2. 您使用了字符串专用函数 strncpy,而 Info 不是一个字符串,所以您需要使用 memcpy

以下代码可以解决问题:

char buffer[sizeof(i)];
memcpy(buffer, &i, sizeof(i));

...

memcpy(&j, buffer, sizeof(j));

还有一个问题,name[5] 不足以容纳"Casey",因为在计算了空字符后它有6个字符。

谢谢。显然应该是sizeof(i)。但我不确定为什么strncpy在这里不起作用,因为char[]紧随int在结构体中,所以没有'\0'来停止复制。 - user1377000
首先,这不是一个好的编程实践。其次,如果int中的某个字节具有零值,会怎样呢? - Oliver Charlesworth
哦,ASCII中的空字符是0 :) - user1377000
我突然想到,在使用赋值运算符回答问题后,你可以在这种情况下通常进行赋值而无需编写赋值运算符。Info不包含指针,因此默认的赋值运算符和复制构造函数将正常工作并进行深拷贝。因此,可以直接使用j = i而不是memcpy(...) - Nikos C.

4

几个问题需要注意:

  • 你正在溢出缓冲区,char name [5]无法容纳“Casey”,终止符不会适合。这会导致未定义的行为。
  • 您正在从&i复制,就好像它是指向字符串的指针一样,但实际上它指向了一个struct,其第一个字段是int。这将无法可靠地工作。

1
+1,我担心当标准库中发现memcpy()时会发生什么。=P - WhozCraig

0
你不需要使用memcpy()函数来复制Info变量。你可以直接使用赋值运算符:
Info j;
j = i;
printf("%d %s", j.age, j.name);

你可以这样做,因为Info不包含指针成员变量,因此在使用赋值运算符时会得到深拷贝。如果只使用默认的复制构造函数,也会发生同样的情况:
Info j(i);

或者:

Info j = i;

当然,正如其他人指出的那样,您应该使Info::name足够大,以容纳您打算存储在其中的名称,包括'\0'字符串终止符。

0

你发布的代码存在几个问题。首先,考虑到“Casey”必须以空字符结尾,infoname 字段太短了。

你所发现的问题是由另一个问题引起的。 j 的地址与其 name 字段不对齐。在那个位置仍然有一个 int age,而最可能的情况是 name 字段在后面 4 个字节开始,但这取决于编译器的自由裁量权。

至于恢复 age,那是行不通的,因为它从未存储到缓冲区中。

可以尝试的方法是,假设 buffer 足够大,使用 memcpy(buffer, &i, sizeof(Info)) 进行存储,并交换前两个参数以进行重构。在这里使用 sizeof 有助于解决问题,因为这样你就可以询问编译器在内存中布局此结构的方式,从而得知结构体 Info 的大小。


我认为名称(而不是年龄)从未存储在缓冲区中,因为(假设年龄为4个字节)年龄的3个字节将为0,这些字节是空字符的ASCII码,因此strncpy将停止,对吗? - user1377000
抱歉我误读了。那是正确的,不过要准确的说,0 是 0,与 ASCII 无关。 - s.bandara

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