我是靠谱客的博主 玩命毛巾,最近开发中收集的这篇文章主要介绍memcpy和memmove的模拟实现,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

1.首先来介绍的是memcpy ,其用法与strcpy类似,都是对字符串进行拷贝,二者可以进行类比学习

memcpy函数语法

函数原型

void *memcpy(void *destin, void *source, unsigned n);

参数

  • destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。

  • source-- 指向要复制的数据源,类型强制转换为 void* 指针。

  • n-- 要被复制的字节数。

返回值

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

功能

从源source所指的内存地址的起始位置开始拷贝n个字节到目标destin所指的内存地址的起始位置中。 

所需头文件

C语言:#include<string.h>

C++:#include<cstring>

2.strcpy和memcpy主要有以下3方面的区别

1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。

2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符""才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。

3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy。 

3.进行模拟实现

void* my_memcpy(void *dest, const void *src, size_t count)//因为memcpy是内存拷贝函数,所以必须什么类型都能接收,所以此处用void*做参数类型和返回值类型

这里的dest代表目标变量,src代表源变量,memcpy就是将源变量src从起始位置拷贝n个字节到目标变量dest的起始位置。

下面就来实现memcpy:基本思想是让两个指针指向dest和src变量,然后当*dest==*src时,让两个指针同时向后移,然后进行循环,一直到count为0,循环结束,此时也就将count个字节的内容全部拷贝完毕。

切记size_t count代表的是字节数。用int a[] = {1,2,3,4,5};来举例:

在内存中的存储为:

01 00 00 0001 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 00

每个整形占4个字节

下面就是代码的实现:

#include<stdio.h>
#include<assert.h>
void*my_memcpy(void* dest, const void* src, size_t count)
{
    assert(dest && src);
    char* start = (char*)dest;
    while (count--)
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest + 1;
        src = (char*)src + 1;
    }
    return start;
}
int main()
{
    int arr1[100] = {};
    int arr2[] = { 1,2,3,4,5 };
    my_memcpy(arr1, arr2, 20);
 
    for (int i = 0; i < 5; i++)
    {
        printf("%d ", arr1[i]);
    }
 
    return 0;
}

到这里,或许你们还会想到一个问题,函数是否能实现自己对自己进行拷贝呢?

这里就需要用到我们的memmove函数了,memcpy和memmove唯一的区别是当内存发生局部重叠时,memmove可以保证拷贝正确,memcpy拷贝的结果是不确定的

1.首先来介绍一下memmove,它可以实现memcpy的所有功能,还解决了memcpy函数不能处理的如果拷贝时出现重叠的情况

​​​​​​​​​​​​​​

函数简介

原型:void *memmove( void* dest, const void* src, size_t count );

头文件:<string.h>

功能:由src所指内存区域复制count个字节到dest所指内存区域。

​​​​​​​

下面先看一张图方便理解一下:

如图所示,我们可以看到两种情况

第一种:目标指针变量dest的起始位置小于源指针变量src的起始位置,这时候我们需要将src指向的内容正着拷贝到dest所指向的空间,所以需要从左向右依次拷贝 。

第二种:目标指针变量dest的起始位置大于源指针变量src的起始位置,这时候我们需要将src指向的内容倒着拷贝到dest所指向的空间,所以需要从右向左依次拷贝。

如果不分情况进行讨论,很有可能会产生覆盖

2.基本思想:

memmove函数模拟实现的时候要考虑拷贝的源字符串与目标字符串的重叠部分,并且以此作为分类的标准。要保证先把重叠部分取出来,拷贝到目标字符串中。

下面是代码的实现:

#include<stdio.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t count)
{
    assert(dest && src);
    char* start = (char*)dest;
    
        if (dest < src)
        {
            while (count--)
            {
                *(char*)dest = *(char*)src;
                dest = (char*)dest + 1;
                src = (char*)src + 1;
            }
        }
        else
        {
            while (count--)
            {
                *( (char*)dest + count) =* ( (char*)src + count);
            }
        }
        return start;
    
}
int main()
{
    int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
    my_memmove((int*)arr1+5,(int*)arr1+3, 20);
    for (int i = 0; i < 10; i++)
    {
        printf("%dn",arr1[i]);
    }
    return 0;
}

到这里函数就实现完成了,还有几点是需要注意一下的:

1.​​​​​​​模拟实现的my_memcpy函数和my_mommeve函数的返回值和参数的类型,必须是void*。因为memcpy函数是内存拷贝函数,它必须什么类型都能接收。

2. dest和src指针变量需要断言,不能为空。并且源指针变量src是不改变的,所以要用const修饰,以起到保护作用

3.void*类型是不能进行解引用操作和++、–运算的,所以进行强制类型转换才能进行解引用操作和++、–-运算,memmove函数是一个字符一个字符拷贝,所以这里要强制类型转换为char*类型。 

4.目标变量dest的地址需要存放在一个临时指针变量中,因为dest在循环体中一直是变化的。临时指针变量变化不会引起dest变化,最后函数返回临时指针变量即可。

最后

以上就是玩命毛巾为你收集整理的memcpy和memmove的模拟实现的全部内容,希望文章能够帮你解决memcpy和memmove的模拟实现所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(52)

评论列表共有 0 条评论

立即
投稿
返回
顶部