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. docker08容器监控工具-WeaveScope

    容器监控工具WeaveScope 一 背景 在生成环境中k8s应用部署众多,需要一款可视化工具方便日常获知集群的实时状态,并为故障排查提供及时和准确的数据支持. weavescope支持docker和 ...

  2. 后端程序员之路 37、Akka、Actor、Scala初窥

    Akkahttp://akka.io/ Akka 是一个用 Scala 编写的库,用于简化编写容错的.高可伸缩性的 Java 和 Scala 的 Actor 模型应用,是一个广泛运用的分布式应用框架. ...

  3. Synchronized 轻量级锁会自旋?好像并不是这样的。

    本来是在写面霸系列的,写着写着就写到了这一题: Synchronized 原理知道不? 而关于 Synchronized 我去年还专门翻阅 JVM HotSpot 1.8 的源码来研究了一波,那时候我 ...

  4. golang操作mysql2

    目录 Go操作MySQL 连接 下载依赖 使用MySQL驱动 初始化连接 SetMaxOpenConns SetMaxIdleConns CRUD 建库建表 查询 单行查询 多行查询 插入数据 更新数 ...

  5. [UNP] IO 复用

    UNP Part-2: Chapter 6. I/O Multiplexing: The select and poll Functions 的读书笔记. 在 这篇博客 的最后,我们对文章中的服务器- ...

  6. 手把手教你Spring Boot2.x整合Elasticsearch(ES)

    文末会附上完整的代码包供大家下载参考,码字不易,如果对你有帮助请给个点赞和关注,谢谢! 如果只是想看java对于Elasticsearch的操作可以直接看第四大点 一.docker部署Elastics ...

  7. .NET 5下的Blazor是否可以大规模正式使用?

    今天在微信群讨论了很多Blazor是否可以正常用的问题.大家争的面红耳赤的. 于是趁着无聊,就水了这么一篇文. 还记得Blazor还在预览版的时候,我就开始关注Blazor了. 那会儿调试Blazor ...

  8. Python--入门接口测试(1)

    1. 什么是接口测试?为什么要做接口测试? 接口测试是测试系统组件间接口的一种测试.接口测试主要用于检测外部系统与系统之间以及内部各个子系统之间的交互点.测试的重点是要检查数据的交换.传递和控制管理过 ...

  9. PicGo 图床配置【工具篇】

    Github图床(舍弃) step1 下载PicGo 下载链接: https://github.com/Molunerfinn/picgo/releases step2 新建仓库作为上传图片的目标地址 ...

  10. android底部导航栏小结

    android自带的有TabHost,但好像无法满足要求, 本文只记录使用 TabLayout + Fragment  和 android 自带的 BottomNavigationView + Fra ...