strcpy、memcpy、memmove实现及讲解

参考链接:内存函数memcpy、memmove原理及模拟实现
strcpy和memcpy的区别

1.strcpy


/*
(1)函数原型
char *strcpy(char *dest, const char *src);

(2)功能
strcpy() 函数用来复制字符串;;strcpy 是依据 \0 作为结束判断的

(3)头文件
#include<string.h>

(4)返回值
  成功执行后返回目标数组指针 dest。

(5)说明
    注意:src 和 dest 所指的内存区域不能重叠,且dest 必须有足够的空间放置 src 所包含的字符串(包含结束符NULL)。
   注意:如果参数 dest 所指的内存空间不够大,可能会造成缓冲溢出(buffer Overflow)的错误情况,在编写程序时请特别留意,或者用strncpy()来取代。
*/

#include<stdio.h>
#include<assert.h>
char* my_strcpy(char* dest, const char* sou)
{
	assert(dest && sou);
	char* ret = dest;
	while (*sou != '\0') 
	{
		*dest = *sou;
		dest++;
		sou++;
	}
    //*(dest++) = '\0';
	return ret;
}

int main()
{
	char arr1[] = "Hello World!";
	char arr2[] = "****************************";

	printf("%s", my_strcpy(arr2, arr1));
    printf("\n");

	return 0;
}

以上代码未放开注释“(dest++) = ‘\0’;”,输出结果为:
在这里插入图片描述
以上代码放开注释
(dest++) = ‘\0’;”,输出结果为:
在这里插入图片描述

2.memcpy

/*
(1)函数原型
void *memcpy(void*dest, const void *src, size_t n);

(2)功能
由src指向地址为起始地址的连续n个字节的数据复制到以destin指向地址为起始地址的空间内。

(3)头文件
#include<string.h>

(4)返回值
  函数返回一个指向dest的指针。

(5)说明
        1.source和destin所指内存区域===不能重叠====,函数返回指向destin的指针。

        2.与strcpy相比,memcpy并不是遇到'\0'就结束,而是==一定会拷贝完n个字节==。

        memcpy用来做内存拷贝,你可以拿它拷贝==任何数据类型的对象==,可以指定拷贝的数据长度;
例:

  char x[100], y[50];
  memcpy(y, x,sizeof(y)); //注意如用sizeof(x),会造成y的内存地址溢出。
  而strcpy就只能拷贝字符串了,它遇到'\0'就结束拷贝;

例:

    char a[100], b[50];
    strcpy(a,b);

    3.如果目标数组destin本身已有数据,执行memcpy()后,将覆盖原有数据(最多覆盖n)。如果要追加数据,则每次执行memcpy后,要将目标数组地址增加到你要追加数据的地址。

  注意:source和destin都不一定是数组,任意的可读写的空间均可。
*/

#include<stdio.h>
#include<string.h>
#include<assert.h>
void * my_memcpy(void *dest, const void* src, int n){
    assert(dest != nullptr);
    assert(src != nullptr);
    assert(n > 0);

    void * retr = dest;

    //有多少个字节执行多少次
    while(n--){
        /*
          只有强制转化为char*才可以实现一个字节一个字节进行赋值
          另外(void*)不能直接解引用
        */
        //一般我们用地址赋值都会先把地址解引用并赋值,然后让地址++。
        /*
          传参的地址都是void*类型的,当我们让地址++,地址不知道要跳几个字节。
          比如:char* 类型的指针++,向后跳1个字节。而int* 类型的指针++,向后跳4个字节。
        */

       /*
        现在我们面临两个问题:
        1.指针类型为void*,无法++。
        2.要拷贝内容的个数不知道,通俗点就是我们不知道要拷贝几次或者两个指针要++几次。

        对于第一个问题,我们把指针强制类型转换,这样就可以++了。但是如果让指针类型转换成int*话,我们就要循环count/sizeof(int)次,这样太麻烦我们还带确定用户要拷贝内容的类型。
        对于这个问题我们可以把指针类型转换成char* ,因为char*类型指针++向后跳一个字节(一个字节一个字节访问),不管是什么类型我们都可以一个一个字节的拷贝,这样我们也容易确定循环次数,为count。
       */

        *(char *)dest = *(char *)src;
        dest = (char*)dest + 1;
        src = (char *)src + 1;
    }
    //注意:我们也不要忘了,要拷贝一下目标地址的起始位置,因为函数要返回目标空间起始地址
    return retr;

}

int main(){
    int array1[] = {1,2,3,4,5,6,7};
    int array2[20] = {0};
    memcpy(array2, array1, 40);
    
    for(int i = 0; i < 40; i++){
        printf("%d  ", array2[i]);
        if((i + 1)%10 == 0)
            printf("\n");
    }
    printf("\n");

    return 0;
}

3.memmove

/*
    (1)函数原型:

        void *memmove(void *str1, const void *str2, size_t n)

    (2)功能:

        从 str2 复制 n 个字符到 str1,但是在==重叠内存块==这方面,memmove() 是比 memcpy() 更安全的方法。如果目标区域和源区域有重叠的话,memmove() 能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中,复制后源区域的内容会被更改。如果目标区域与源区域没有重叠,则和 memcpy() 函数功能相同。

    (3)头文件:

        #include <string.h>

    (4)返回值:

        该函数返回一个指向目标存储区 str1 的指针。

    (5)说明:

         memcpy()函数如果遇到内存重叠,就无法得到理想的拷贝。而memmove()函数就恰恰解决了这一问题。
*/
#include<assert.h>
#include<stdio.h>

void * my_memmove(void * dest, const void * src, int n){
    assert(dest != nullptr);
    assert(src != nullptr);
    assert(n > 0);

    void *ret = dest;
    
    
    if(dest < src || (dest > src + n)){正常情况下从前向后拷贝,和memcpy一样
        while(n--)
        {
            *(char *)dest = *(char *)src;
            dest = (char *)dest + 1;
            src = (char *)src + 1;
            //++(char *) dest;
            //++(char *)src;
        }

    }else{
        //有重叠
        //当出现内存覆盖时从后向前拷贝
        while(n--){
            *((char *)dest + n) = *((char *) src + n);
        }
    }

    return ret;
}


int main()
{
	char arr[10] = "abcdefg";
	char arr0[10] = "abcdefg";
	char arr1[10] = { 0 };
	my_memmove(arr + 2, arr, 4);//内存覆盖
	my_memmove(arr1, arr0, 4);
	printf("%s\n", arr);
	printf("%s\n", arr0);
	printf("%s\n", arr1);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值