C语言进阶--内存函数的使用与模拟实现

目录:

memcpy函数

函数memcpy定义:

简单的使用方法介绍:

memcpy的模拟实现

memmove函数

函数memeove定义:

简单的使用方法介绍:

memcpy的模拟实现

画图分析:

代码实现

关于memcp和memmove该如何选择

memcmp函数

函数memcmp的定义:

简单的使用方法介绍:

memset函数

函数memset的定义:

简单的使用方法介绍:

错误用法:

memcpy函数

使用时要使用<string.h>头文件

函数memcpy定义:

void * memcpy ( void * destination, const void * source, size_t num );

简单的使用方法介绍:

  • 函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。

  • 这个函数在遇到 '\0' 的时候并不会停下来

  • 如果source和destination有任何的重叠,复制的结果都是未定义的。


memcpy的模拟实现

void* my_memcpy(void* dest, const void* src, size_t num)
{
  *(char*)dest = *(char*)src;
  //(*(char*)dest)++;
  //(*(char*)src)++; 
  dest=(char*)dest+1;
  src= (char*)src+1;
}

因为传的是字节,所以这里强制转换为char类型,一个一个字节来拷贝;强制转换是临时性的,因此若想再往后移一个字节,需要重新强制转换,而4,5行代码不能保证任何情况下都是对的,因此我们可以使用6,7行代码的形式。

void* my_memcpy(void* dest, const void* src, size_t num)
{
   assert(dest && src);
   while(num--)
  {
       *(char*)dest = *(char*)src;
  //(*(char*)dest)++;
  //(*(char*)src)++; 
  dest=(char*)dest+1;
  src= (char*)src+1;
  }
}

这里我们可以用while循环拿num来判断循环是否停止,并且可以用assert来断言一下,若是传来的有空指针,程序便不会执行下去,会使程序更加安全,assert的头文件是<assert.h>。

程序执行情况:

int main()
{
  int arr1[]={1,2,3,4,5,6,7,8,9,10};
  my_memcpy(arr1+2,arr1,20);
  for (int i = 0;i < 10;i++)
    {
      printf("%d ", arr1[i]);
    }
  retunrn 0;
}

上面的代码的理想情况应该是:1 2 1 2 3 4 5 8 9 10

那么实际输出又是什么呢?

我们可以看到,和我们预期的结过并不一样,其实是因为arr1一直在被改变,发生了内存重叠(直接使用memove函数可以解决这个问题,后面我们会介绍这个函数)。我们的理想情况是3,4,5,6,7被替换为1,2,3,4,5,但是在替换过程中3,4替换1,2,而5,6原本是应该替换为3,4,但3,4被替换为了1,27应该替换为5,但5已经被替换为1。

memmove函数

函数memeove定义:

void * memmove ( void * destination, const void * source, size_t num );

简单的使用方法介绍:

  • 和memcpy的差别就是memmove函数处理的源内存块和目标内存块可以重叠的。

  • 如果源空间和目标空间出现重叠,就得使用memmove函数处理。


memcpy的模拟实现

画图分析:

  • 我们不难发现,当dest(目标)的首元素在src(源)的首元素的右边时,我们将src的最后一个元素拷贝给dest的最后一个元素,这样子从后往前拷贝,就不会覆盖要拷贝的内容了

  • 当dest(目标)的首元素在src(源)的首元素的左边时,我们将src的第一个元素拷贝给dest的第一个元素,这样子从前往后拷贝,就不会覆盖要拷贝的内容了

  • 我们再整理一下结合上面的图便可以得出这个结论

代码实现

void* my_memmove(void* dest, const void* src, size_t num)
{
     assert(dest && src);
    //前-->后
    if (dest < src)
    {
        while (num--)
        {
            *(char*)dest = *(char*)src;
            dest = (char*)dest + 1;
            src = (char*)src + 1;
        }
    }
    //后-->前
    else
    {
        while(num--)
        {
            //num为后置--,判断完后-1,例如传的是20,那么(char*)dest + num刚好指向要拷贝的第20个字节
            *((char*)dest + num) = *((char*)src + num);
        }
    }
}

dest<src

dest>src

关于memcp和memmove该如何选择

上文中,我们自己实现的memcpy不能应对内存重叠的问题,如果你用给的现成的memcpy可以输出预期结果,但是这并不能保证永远是对的:

在C语言中:1.memcpy拷贝不重叠的内存

2. 重叠的就交给memmove

3.可以理解为使用memmove想考100分,用memcpy及格就行了

memmove>memcpy

VS编译器中:memmove和memcpy都考了100分,但不能保证其他编译器也是如 此,在其他编译器若是也想使用memcpy拷贝重叠的内存,可以先进行测试一下。

3.那么为什么有了memove还要又memcpy,这就可能涉及到历史遗留问题,memcpy可能是先出现的,memmove后来的,但是不能随便删改库函数,因为这样子早期用到了删掉的库函数的代码就无法被新的编译器或语法所兼容

memcmp函数

函数memcmp的定义:

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

简单的使用方法介绍:

  • 比较从ptr1和ptr2指针开始的num个字节

  • 返回值如下:

memset函数

函数memset的定义:

void * memset ( void * ptr, int value, size_t num )

简单的使用方法介绍:

参数:


ptr

指向要填充的内存块的指针。

value

要设置的值。该值作为 int 传递,但该函数使用此无符号 char 转换填充内存块。

num

要设置为该值的字节数。

size_t 是无符号整数类型。

错误用法:

  • 13
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱敲爱骑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值