C语言函数strcpy、strncpy、memcpy、memmove函数的区别以及一些坑

一、函数说明

1、strcpy函数

char* strcpy(char* dest, const char *src);

说明:

函数strcpy把src指向的串(包括空字符)复制到dest指向的数组中。如果复制发生在两个重叠的对象中,则这种行为未定义,其中如果中间字符遇到'\0'停止复制。

返回值:

函数strcpy返回dest的值。

举例:

#include<stdio.h>
#include<string.h>

char str[4];
int main()
{
    strcpy(str,"abc");
    printf("%s\n",str);
    return 0;
}

结果:

[wanghe@localhost ~]$ gcc test_string.c -o test_string.exe
[wanghe@localhost ~]$ ./test_string.exe 
abc

2、strncpy函数

char* strncpy(char* dest, const char* src, size_t count);

说明:

函数strncpy从src指向的数组中最多复制count个字符(不复制空字符后面的字符)到dest指向的数组中。如果复制发生在两个重叠的对象中,则这种行为未定义,其中如果中间字符遇到'\0'停止复制。

如果src指向的数组是一个比n短的字符串,则在dest定义的数组后面补空字符,直到写入了count个字符。

返回值:

函数strncpy返回dest的值。

举例(注意复制长度是2):

#include<stdio.h>
#include<string.h>

char str[4];
int main()
{
    strncpy(str,"abc",2);
    printf("%s\n",str);
    return 0;
}

 结果:

[wanghe@localhost ~]$ gcc test_string.c -o test_string.exe
[wanghe@localhost ~]$ ./test_string.exe 
ab

3、memcpy函数

void* memcpy(void *dest,  const void *src,  size_t  count);

说明:

函数memcpy从src指向的对象中复制count个字符到dest指向的对象中。如果复制发生在两个重叠的对象中,则这种行为未定义。

返回值:

函数memcpy返回dest的值。

举例:

#include<stdio.h>
#include<string.h>

char str[4];
int main()
{
    char tmp[] = "abc";
    memcpy(str,tmp,3);
    printf("%s\n",str);
    return 0;
}

结果:

[wanghe@localhost ~]$ gcc test_string.c -o test_string.exe
[wanghe@localhost ~]$ ./test_string.exe 
abc

 4、memmove函数

void* memmove(void* dest, const void* src, size_t count)

说明:

memmove函数的功能同memcpy基本一致,但是当src区域和dest内存区域重叠时,memcpy可能会出现错误,而memmove能正确进行拷贝。

返回值:

函数memmove返回dest的值。

举例(长度是2):

#include<stdio.h>
#include<string.h>

char str[4];
int main()
{
    char tmp[] = "abc";
    memmove(str,tmp,2);
    printf("%s\n",str);
    return 0;
}

结果:

[wanghe@localhost ~]$ gcc test_string.c -o test_string.exe
[wanghe@localhost ~]$ ./test_string.exe 
ab

二、函数对比与问题

1.strcpy与strncpy

strcpy函数是复制字符串,遇到'\0'结束复制,这其中的问题是如果目标空间长度小于源字符串长度,会导致原本的内存数据被覆盖。

举例:

#include<stdio.h>
#include<string.h>

int main()
{
    char d[5] = {0};
    char s[] = "hello world";
    strcpy(d,s);
    return 0;
}

也许运行结果可能觉得没有问题,但实际上会覆盖原本不属于d的内存,导致内存。所以可以采用strncpy函数,strncpy函数是复制n个字符到目标地址。

比如上述程序可以改写成:

#include<stdio.h>
#include<string.h>

int main()
{
    char d[5] = {0};
    char s[] = "hello world";
    strncpy(d,s,sizeof(d)-1);
    printf("%s\n",d);
    return 0;
}

虽然没有复制完全,但是不会出现内存问题。为什么是sizeof(d)-1呢?主要是由于strncpy是不会复制'\0'的,这一点要特别注意!

但是strncpy函数也有它的一些问题:

(1)内存越界问题,如果复制的字符数量n > 目标空间长度,就会越界

(2)字符串结束标志符'\0'丢失,当源字符串的长度 == 目标空间大小时,调用strncpy使得目标字符串结束标志符'\0'丢失。

举例:

#include<stdio.h>
#include<string.h>

int main()
{
    char d[20] = "abcd efg";
    char s[] = "he";
    strncpy(d,s,sizeof(s)-1);
    printf("%s\n",d);
    return 0;
}

结果:

[wanghe@localhost ~]$ gcc test_string.c -o test_string.exe
[wanghe@localhost ~]$ ./test_string.exe 
hecd efg

从结果上可以看出,复制结束后是不会在尾部加'\0'的,这意味着如果复制字符串的长度和目标空间大小相等,那么存储的'\0'就会被覆盖,这会导致错误!

(3)效率较低,当 n > 源字符串长度时,会继续填充'\0'直到count长度为止。

举例:

#include<stdio.h>
#include<string.h>

int main()
{
    char d[20] = "abcd efg";
    char s[] = "he";
    strncpy(d,s,4);
    int i = 0;
    for(i = 0;i < 8;i++)
        printf("%c\n",d[i]);
    return 0;
}

执行结果:

[wanghe@localhost ~]$ gcc test_string.c -o test_string.exe
[wanghe@localhost ~]$ ./test_string.exe 
h
e


 
e
f
g

(4)不能处理源字符串和目标地址内存交叠情况的字符串拷贝,这一点需要使用memmove函数。

2.strcpy与memcpy

strcpy函数和strncpy函数在复制字符串的时候遇到 '\0'就会结束,因为函数默认'\0'到达了字符串尾部,但如果要复制的字符串中间有0,那么就会没有复制完全就结束了,这显然不符合预期。

举例:

#include<stdio.h>
#include<string.h>

int main()
{
    char d[20] = "ab\0cd efg";
    char s[12] = {0};
    strcpy(s,d);
    int i = 0;
    for(i = 0;i < 12;i++)
        printf("%d ",s[i]);
    return 0;
}

结果:

[wanghe@localhost ~]$ gcc test_string.c -o test_string.exe
[wanghe@localhost ~]$ ./test_string.exe 
97 98 0 0 0 0 0 0 0 0 0 0 

所以如果字符串中有'\0'就不能用strcpy和strncpy函数了,必须采用内存复制函数,如memcpy函数。

举例:

#include<stdio.h>
#include<string.h>

int main()
{
    char d[20] = "ab\0cd efg";
    char s[12] = {0};
    memcpy(s,d,sizeof(d)-1 );
    int i = 0;
    for(i = 0;i < 12;i++)
        printf("%d ",s[i]);
    return 0;
}

结果:

[wanghe@localhost ~]$ gcc test_string.c -o test_string.exe
[wanghe@localhost ~]$ ./test_string.exe 
97 98 0 99 100 32 101 102 103 0 0 0 

因为有0,所以直接输出字符串是看不到具体效果的,所以输出ASCII值。

3.memcpy与memmove

前面提到了无论是strncpy还是memcpy函数,都有一个缺陷那就是如果源地址和目标地址内存上有重叠,在C语言中是未定义行为,结果可能会出现问题,所以为了避免这一情况,采用memmove函数。

首先如果源地址在目标地址后面,那么不会有什么问题。

 

如果是在前面,那么复制的时候会改变本身的值,原则上应该是倒序复制,这样就可以避免,但是memcoy函数是从左到右顺序复制的,所以无法处理内存重叠问题。

memmove函数是在执行的时候会去判断源地址和目标地址是否重叠,如果重叠会倒序复制顺序使得不会冲突。

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值