C语言中的内存函数有如下这些

  • memcpy
  • memmove
  • memcmp
  • memset

下面看看memmove函数

memmove

为什么会需要memmove函数?

int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int i = 0;
// 想把12345 拷贝到 34567上去
// 应该打印 1 2 1 2 3 4 5 8 9 10
my_memcpy(arr + 2, arr, 20); for (i = 0; i < 10; i++)
{
printf("%d ", arr[i]);
}
// 但是输出 1 2 1 2 1 2 1 8 9 10 return 0;
}

上面会输出 1 2 1 2 1 2 1 8 9 10,我们来看看为什么会出现这样的结果。

我这里画了张图,方便理解。

因为拷贝的地方重叠了,使原来的数据(3 4 5)被覆盖了,导致最后出来的结果不是我们想要的。

也就是说,如果拷贝的地方重叠了,那么就会出现这种情况。

那么如何解决呢?答案就是从后往前拷贝,指针从最后的地方开始操作。

还是上一张图

这样,就得出了我们想要的结果。

但是呢,也不能一概而论,就全部都是从后往前拷贝,还是得分情况的,具体就是看destinationsource的位置关系。

回到最开始的问题,为什么会需要memmove函数?,因为memmove这个函数可以处理这种重叠拷贝。

老规矩,我们还是看看文档是怎样说的,如下

memmove文档

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

Move block of memory

移动内存块(移动内存数据)

Copies the values of num bytes from the location pointed by source to the memory block pointed by destination. Copying takes place as if an intermediate buffer were used, allowing the destination and source to overlap.

从source(源内存块位置)直接指向的地方开始复制num个字节的数据到destination指向的内存块位置。然后复制就像使用了中间缓冲区一样,允许destination和source重叠。

The underlying type of the objects pointed by both the source and destination pointers are irrelevant for this function; The result is a binary copy of the data.

这句话没看懂,不影响我们学这个。

The function does not check for any terminating null character in source - it always copies exactly num bytes.

这个函数不会检查'\0',不会遇到'\0'就停下来,它就只认识要复制的num个字节数据。

To avoid overflows, the size of the arrays pointed by both the destination and source parameters, shall be at least num bytes.

为了避免溢出,这两个数组的大小至少为num个字节。

可以看出,memmove和memcpy的唯一区别就是,memmove函数处理的源内存块和目标内存块是可以重叠的。

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

实现

断言指针不为空是个好习惯~

void* my_memmove(void* dest, void* src, size_t num)
{
//dest落在了src的左边,从前往后拷贝
//dest落在了src的右边,同时没有超过那个重叠的边界的时候,从后往前拷贝
assert(dest != NULL);
assert(src != NULL);
void* rest = dest;
// void* 不能直接解引用,那么如何复制呢?
// 给了num个字节,也就是需要复制num个字节
// 那就转换成char*,一个一个字节的复制过去
if (dest < src)
//if (dest < src || dest > (char*)src + num)
{
//dest落在了src的左边,从前往后拷
while (num--)
{
*(char*)dest = *(char*)src;
//++(char*)dest;
//++(char*)src;
((char*)dest)++;
((char*)src)++;
}
}
else
{
// 从后往前拷
// 找到最后一个字节
while (num--)
{
*((char*)dest + num) = *((char*)src + num);
} }
return rest;
}

最后,感谢屏幕前靓仔花宝贵的时间阅读我这篇博客~

本人水平有限,如有错误以及不足之处,欢迎靓仔指出。

C语言-内存函数的实现(二)之memmove的更多相关文章

  1. C语言-内存函数的实现(一)之memcpy

    C语言中的内存函数有如下这些 memcpy memmove memcmp memset 下面看看memcpy函数 memcpy 我们想想,之前有那个字符串拷贝的函数,即strcpy函数.都有拷贝的函数 ...

  2. C语言内存函数

    http://see.xidian.edu.cn/cpp/u/hs3/ 函数 说明 calloc() 分配内存空间 free() 释放内存空间 getpagesize() 取得内存分页大小 mallo ...

  3. C语言 mmap()函数(建立内存映射) 与 munmap()函数(解除内存映射)

    mmap将一个文件或者其它对象映射进内存.文件被映射到多个页上,如果文件的大小不是所有页的大小之和, 最后一个页不被使用的空间将会清零.mmap在用户空间映射调用系统中作用很大. 条件 mmap()必 ...

  4. Go语言学习——函数二 defer语句

    函数 package main import "fmt" // 函数:一段代码的封装 func f1(){ fmt.Println("Hello 中国!") } ...

  5. 【C语言】函数和自定义函数

    函数,我之前也提到过一点点内容.其实函数是很好理解的,但是写起来又十分麻烦. 一.     函数引入 我们知道,C源程序是由函数组成的.请看下面的简单函数例子 #include <stdio.h ...

  6. c语言之函数指针

    一.基础研究 这里研究的内容是函数指针,需要我们在研究后构造程序来描述函数指针数组的用法和向函数传函数指针的方法. 指针有很多种:整型指针.结构体指针.数组指针等等,它们的本质是它们的值都是一个地址, ...

  7. c语言内存模型

    文章一.C语言的内存分配模型 1.程序代码区:存放函数体的二进制代码. 2.全局区数据区:全局数据区划分为三个区域.全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化 ...

  8. C语言内存四区的学习总结(一)---- 静态区

    最近重新学习C语言相关知识,重新提到内存四区的概念,那么在之前的学习的基础上,在这儿做一个简单的总结与分享. 一.内存四区建立的流程 可以简单直观的查看下面的这个图片,直接的说明我们的程序在内存中是如 ...

  9. [c/c++] programming之路(23)、字符串(四)——strncat,atoi,strcmp,strlen等,以及常用内存函数

    一.strncat及自行封装实现 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #i ...

随机推荐

  1. Django Admin 删除文件同时删除资源文件(delete_upload_files)

    一  使用环境 开发系统: windows IDE: pycharm 数据库: msyql,navicat 编程语言: python3.7  (Windows x86-64 executable in ...

  2. Flannel和Calico网络插件工作流程对比

    Flannel和Calico网络插件对比   Calico简介 Calico是一个纯三层的网络插件,calico的bgp模式类似于flannel的host-gw Calico方便集成 OpenStac ...

  3. C#测试--内部类测试

    C#测试--内部类测试 在被测试的代码库的AssemblyInfo.cs中添加"[assembly: InternalsVisibleTo("UnitTest项目名称") ...

  4. CSS元素层级的概念及性质

    元素的层级的介绍 什么是元素的层级 通过z-index可以改变开启定位元素的层级 父元素的层级再高也不会遮盖住子元素 元素的层级的介绍 什么是元素的层级 当元素开启定位后就会是元素提升一个层级,网页是 ...

  5. Element 文档中的 Markdown 解析

    Element 的文档站是讲Markdown解析成vue组件在页面中渲染出来,转换过程如下图所示: 红框部分势必要对 Markdown 进行特殊的订制,订制过的 Markdown 像下面这样. ::: ...

  6. POJ-3436(网络流+最大流+输出路径)

    ACM Computer Factory POJ-3436 题目就是一个工厂n个加工机器,每个机器有一个效率w,q个材料入口,q个材料出口,每个口有三个数表示状态,1表示一定有入/出的材料,0表示没有 ...

  7. JAVA-标识符、变量、数据类型

    标识符和关键字 ​ 所有的标识符否应该以字母a ~ z和 A ~Z ,美元符($).下划线(_)开始. ​ 首字符之后可以是字母a ~ z和 A ~Z ,美元符($).下划线(_)的任意字符组合. 注 ...

  8. Android之Parcelable解析

    http://www.cnblogs.com/abinxm/archive/2011/11/16/2250949.html http://www.cnblogs.com/renqingping/arc ...

  9. FZU_1608 Huge Mission 【线段树区间更新】

    一.题目 Huge Mission 二.分析 区间更新,用线段树的懒标记即可.需要注意的时,由于是在最后才查询的,没有必要每次更新都对$sum$进行求和.还有一点就是初始化的问题,一定记得线段树上每个 ...

  10. 1x1卷据层的作用

    1. 尽管1x1的卷据不会捕捉空间特征(spatial features/patterns,直观点说就是2D平面图的纹理特征),但是他们能很好基于通道(channel-wise/along the d ...