strncpy()和memcpy()有什么不同?

3

strncpy()memcpy() 是一样的吗?

由于 strncpy() 只接受 char * 作为参数,所以将整数数组强制转换为 char *。

为什么会得到不同的输出结果呢?

这是我的代码:

#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <string.h>
#define SIZE 5


void print_array(int *array, char *name ,int len) {
    int i;
    printf("%s ={ ",name);
    for(i=0; i<len;i++)
        printf("%d," ,array[i]);
    printf("}\n");
}

int main(void){
    char string1[SIZE] = {'1','2','3','4','\0'};
    char string2[SIZE], string3[SIZE];
    int array1[SIZE] = {1,2,3,4,5};
    int array2[SIZE],array3[SIZE];

    strncpy(string2,string1,sizeof(string1));
    memcpy(string3, string1,sizeof(string1));
    printf("string2 =%s \n",string2);
    printf("string3 =%s \n",string3);

    strncpy((char *)array2, (char*)array1 , sizeof(array1));
    memcpy(array3,array1,sizeof(array1));
    print_array(array2,"array2",SIZE);
    print_array(array3,"array3",SIZE);

    return 0;
}

原来如此
string2 =1234
string3 =1234
array2 ={ 1,0,0,0,0,}
array3 ={ 1,2,3,4,5,}

但为什么?它给出不同的答案?

2个回答

12
strncpy((char *)array2, (char*)array1 , sizeof(array1));
array1转换为char *并不能达到您想要的效果。在该位置没有字符,只有整数(似乎是小端)。发生的情况是,strncpy从整数数组中复制字节直到遇到一个零字节,这很快就会发生。另一方面,memcpy不关心零字节,只是复制整个字符串。
换句话说,strncpy在第一个整数“内部”找到一个0字节并停止复制;但是它确实向目标缓冲区填充了零直到指定大小。

strncpy() 停在第二个字节,因为整数 1(作为字节)是 0x01、0x00、0x00、0x00(x86 是小端)。这很容易验证。 - Emmet
strncpy实际上并不在零字符处“停止”。它停止读取源数据,但不会停止写入目标缓冲区。目标缓冲区的其余部分将填充为零。 - AnT stands with Russia

1
你可以使用memcpy实现(有点像)strncpy,但反过来是行不通的,因为strncpy会在“字符串的末尾”处停止,这对于不是C语言风格字符串的数据(例如其中有零字节)根本不起作用。
使用memcpy编写strncpy将是这样的:
char *strncpy(char *dest, const char *src, size_t maxlen)
{
   size_t len = strlen(src);
   memcpy(dest, src, min(len, maxlen));
   if (len < maxlen) memset(dest+len, 0, maxlen-len);
   return dest;
}

(注意:上述实现无法处理未正确终止的src字符串的情况 - 真正的strncpy可以处理这种情况 - 可以在上述代码中进行修复,但会变得非常复杂。)

请注意,这是一种质量较差的实现,因为它需要两次处理字符串。同时,您可以使用strncpy来实现memcpy,只不过它每次遇到零字节就必须重新开始,这非常低效,尤其是在源数据全部为零的情况下更是如此。 - R.. GitHub STOP HELPING ICE
@R.. 没错,我同意实现很差。但在第二种情况下,我看不出你如何能以任何方式完成它,而不是多次处理数据,并基本上只使用strncpy一次或几个字节一次地复制。有点像用塑料勺子在花园里挖鱼池。给足够的时间,这是可能的,但这是非常低效和繁琐的工作。 - Mats Petersson
@Mats Petersson:该实现根本不模拟标准的strncpystrncpy不是一个有限长度的字符串复制函数。 strncpy是一个转换函数,将以零结尾的字符串转换为固定宽度的字符串。其至关重要的特点是它用零填充目标缓冲区的尾部。您的版本没有这样做,即您实现的不是strncpy - AnT stands with Russia
@AndreyT:好的,我必须承认我从来没有(至少我能回忆起来的时候 - 当你工作了25年或更长时间时,你做过什么或没做过什么有时会变得模糊)使用strncpy来复制一个没有正确终止的字符串[它可能在我停止复制的位置之后很好地终止,这是另一回事]。我认为我已经解决了你的主要问题,但并没有解决“输入可能没有以零结尾”的问题。这并不是指“这是一个适当的实现”,而是为了显示关系。 - Mats Petersson

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