struct复制中memcpy和strncpy的区别

3

我有以下代码。我试图将一个结构体复制到一个字符串中。我想知道为什么使用strncpy和memcpy输出结果不同。

#include <stdio.h>
#include<string.h>
struct a{
    int len;
    int type;
};
int main(){
    struct a aa={98,88};
    char str[10]="";
    char str2[10]="";

    strncpy(str,&aa,sizeof(struct a));
    memcpy(str2,&aa,sizeof(struct a));
    for(int i=0;i<10;i++)printf("%2d",str[i]);
    printf("\n");
    for(int i=0;i<10;i++)printf("%2d",str2[i]);

    return 0;
}

以下是输出结果:
98 0 0 0 0 0 0 0 0 0
98 0 0 088 0 0 0 0 0

我理解strncpy会复制直到遇到'\0'(或大小限制),但是在结构体中我没有'\0'值。请有人帮我理解一下。
这样做的目的:尝试通过网络发送一个结构体。虽然我计划实现序列化,但我想了解其行为。
编辑: 1)由Keith Thompson建议
下面是生成的警告。
incompatible pointer types passing 'struct a *' to parameter of type 'const char *' [-Wincompatible-pointer-types]

2) 我稍微修改了代码,使用了int数组:

(仅供参考。我理解在这种情况下,由于数组大小足够存储结构体变量的前两个元素,memcpy会将结构体变量的变量复制到数组中的前两个元素中。)

#include <stdio.h>
#include<string.h>
struct a{
    int len;
    int type;
};
int main(){
    struct a aa={98,88};
    int str[10]={0};
    int str2[10]={0};

    strncpy(str,&aa,sizeof(struct a));
    memcpy(str2,&aa,sizeof(struct a));
    for(int i=0;i<10;i++)printf("%2d",str[i]);
    printf("\n");
    for(int i=0;i<10;i++)printf("%2d",str2[i]);

    return 0;
}

以下是问题:

98 0 0 0 0 0 0 0 0 0
9888 0 0 0 0 0 0 0 0

以下是生成的警告:
incompatible pointer types passing 'int [10]' to parameter of type 'char *' [-Wincompatible-pointer-types]
incompatible pointer types passing 'struct a *' to parameter of type 'const char *' [-Wincompatible-pointer-types]

你的结构体不是一个字符串。strncpy 是用于操作字符串的。那个调用甚至不应该编译通过;你至少应该得到一个警告,因为你传递了一个 struct a* 参数给 strncpy,而它期望的是一个 char*。即使对于字符串,通常也应该避免使用 strncpy在这里看看我对此的抱怨 - Keith Thompson
它确实抛出了一个警告。 - mayur
请更新您的问题以显示确切的警告信息;这是非常重要的信息。 - Keith Thompson
感谢 @KeithThompson 添加警告。还添加了另一个例子。 - mayur
3个回答

2

但是在结构体中没有 '\0' 值。

实际上,您至少有六个 '\0':假设 int 是 32 位的,则 9888 的上三个字节都是零。它们会使 strncpy 停止复制。该函数设计用于固定长度的字符串,因此不应将其与任意的 struct 一起使用。另一方面,memcpy 将复制所有内容。

这样做的目的是:尝试通过网络发送一个结构体。

如果您想通过网络发送您的 struct,并且您希望数据包可移植,请在发送方将两个 int 转换为网络顺序,并在接收方将其转换回硬件顺序。对于 32 位数字,请使用 htonlntohl 函数


谢谢,我忘了'\0'等于0。strcpy会在遇到0时停止。 - mayur

1

memcpy复制字节,strcpy复制以nul结尾的字符串(nul是0字节,0x00,'\x00')。

memcpy始终复制指定数量的字节。当strcpy找到nul时停止复制。


1

但是在结构体中确实有'\0'值。您的整数值具有0位,可以在将字节数据解释为字符时解释为'\0'。由于strncpy按“逐个字符复制直到达到终止符”的方式工作,这会导致它提前停止。

memcpy始终复制指定数量的字节,因此在这种情况下更适用。它是更合适的选择。


谢谢,我错过了那个 '\0' 等于 0。 - mayur

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