手撕strcpy、strncpy与memcpy

文章详细介绍了C语言中的字符串拷贝函数strcpy和strncpy,以及内存拷贝函数memcpy的使用。strcpy用于字符串拷贝,遇到结束,可能导致内存溢出。strncpy增加了长度限制,但需注意防止未填充。memcpy则进行无类型检查的内存块拷贝,适用于任何数据类型,但需处理重叠区域问题。同时,文章强调了类型安全和防止数据截断的重要性。
摘要由CSDN通过智能技术生成

strcpy、strncpy与memcpy是经常使用的拷贝函数,前者用于字符串的拷贝,遇到‘\0’则停止,后者为拷贝n个字符,memcpy为将某块内存拷贝到另一个内存中。

首先看看strcpy的原型声明:char *strcpy(char* dest, const char *src)

接着是具体实现:

char* self_strcpy(char* dest, const char* src) {
    assert(dest != nullptr && src != nullptr);
    char* res = dest;
    while ((*res++ = *src++) != '\0');
    return res;
}

注意:需要检查源字符串与目标字符串是否有地址为空的.

为什么返回值要是char*类型?

为了满足链式表达式,如stcpy(a, strcpy(b, c))

存在的问题:strcpy的本质就是将源字符串的字符逐个拷贝到目标字符串中,当然会拷贝'\0',当拷贝'\0'时就会结束循环,但是当src的长度大于dest时,函数仍然会继续拷贝,此时就会出现内存溢出的问题。

为了解决该问题,可以使用strncpy:声明如下char *strncpy(char *dest, const char *src, int n),具体实现如下:

char* self_strncpy(char* dest, const char* src, int n) {
    assert(dest != nullptr && src != nullptr);
    char* res = dest;
    while (n-- && (*res++ = *src++) != '\0');
    return res;
}

实际上就是加了n,方便程序员对其进行限制,当然如果你设定的n大于目标字符串的大小仍然会溢出。

注意:要根据输入的长度做一个控制,而往往我们使用的时候,输入的长度都是目标字符串的长度减1,因为要留一个位置给结束符'\0'

接着我们写一个memcpy,声明为void *memcpy(void *destin, void *source, unsigned n),具体实现 如下:

void* self_memcpy(void* dest, const void* src, int n) {
    assert(dest != nullptr && src != nullptr);
    char* pdest = static_cast<char *>(dest);
    const char* psrc = static_cast<const char *>(src);
    if (pdest > psrc && pdest < psrc + n) {
        for (int i = n - 1; i >= 0; --i) pdest[i] = psrc[i];
    } else {
        for (int i = 0; i < n; ++i) pdest[i] = psrc[i];
    }
    return dest;
}

有几个需要注意的点:

1、为什么不需要判断'\0’了?

显然,memcpy是一个内存到另一个内存的拷贝,类型不确定,不一定是字符串,也不存在着以‘\0’结尾的说法。

2、为什么使用static_cast

传入的参数具体类型不确定,采用显式转换的方法保证类型安全。

3、为什么要加两个if判断

为了避免地址重叠的问题,当目标地址首部大于源地址首部,但源地址末尾又大于目标地址时即发生了重叠,如果从前向后拷贝会导致拷贝到重复的元素。

反之亦然,如果目标地址首部小于源地址首部,但目标地址末尾又大于源地址首部则从后向前拷贝会导致拷贝到重复的元素。

4、为什么要用char*类型进行判断,用int*类型可以吗?

如果采用int*类型,可能会导致部分数据被截断,同理,在使用memcpy的时候,n最好设置为sizeof(参数类型)* 拷贝数量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值