内存操作函数【快速了解内存函数的作用和实现】

2023-11-17


前言

对于字符串有一系列的字符串函数来操作字符串,比如strcpy、strcmp、strstr。但是这些函数都是只能用来操作字符串的,如果我们想要用来操作其他类型的数据的话就会有问题。这时就有一系列的内存操作函数来供我们使用,帮助我们更好地进行开发和工作。


内存操作函数的共性

我们先来找一找内存操作函数的共性,首先是看函数的定义部分,观察他们的返回类型,还有参数类型。

memcpy 函数的定义

在这里插入图片描述

memmove 函数的定义

在这里插入图片描述

memcmp 函数的定义

在这里插入图片描述

函数的共性

可以这些函数在定义的时候都是将需要操作的空间的使用void* 类型的形参来接受,为什么需要使用 void* 类型的指针来接受这个参数呢,这是因为函数的实现这并不知道会有什么类型的数据传进来,所以需要将函数的参数设为 void* 类型的指针(可以转变和接收为任意类型的指针)。而这些函数在传参的时候都会有一个size_t num 这是说明函数需要操作的空间大小,单位是字节。由于函数在实现的时候,操作的是空间大小的单位是字节。所以在模拟实现的时候就需要将指针转化为字符指针,因为字符指针刚好是一个字节一个字节操作的。

memcpy 函数【内存拷贝函数】

memcpy函数的定义

既然是函数,我们就需要将函数的返回类型还有参数的类型搞清楚,这样可以帮我们更好地掌握这个函数。
memcpy函数的定义

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

memcpy 函数,是将源空间后面的num个字节拷贝到目标空间后面的num个字节上。

模拟实现memcpy 函数

我们只需要将从source开始到source + num - 1 的数据拷贝到从destination 开始,到destination + num - 1 的地址上去就可以了。

void* my_memcpy(void* dest, const void* src, size_t count) {
	assert(dest && src); 	//判断指针不是空指针
	void* ret = dest;		//保留目标空间的起始位置
	while (count--) {	//控制循环保持在0 ~ count - 1
		*(char*)dest = *(char*)src;		//将源空间的内容一个字节一个字节地拷贝到目标空间
		(char*)dest = (char*)dest + 1; 	  //目标空间指向目标空间的下一个字节的地址
		(char*)src = (char*)src + 1;	  //源空间指向源空间的下一个字节的地址
	}
	return ret;     //返回目标空间的起始地址
}

使用前
在这里插入图片描述

使用后
在这里插入图片描述

memmove 函数

memcpy 函数在实现的时候如果目标空间和源空间存在空间重叠,那么就有可能将目标空间的值改变,然后拷贝到后面的目标空间。这样就达不到想要的效果。

使用前
在这里插入图片描述

使用后
在这里插入图片描述

所以需要一个memmove 来解决这一问题

memmove 函数的定义

memmove 函数的定义

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

memmove 函数的模拟实现

解决这一问题,我们可以将源空间的内容拷贝到一个额外的空间里面,然后将这个额外的空间赋给目标空间,但是这种方法就需要额外的空间还有时间,效率有点低。所以我们需要一种更高效的方法,可以看到,如果目标空间的起始地址大于源空间的起始地址的时候,只需要从后面往前拷贝就行了,当目标空间的起始小于起始地址的时候,只需要按照从后往前拷贝的方式来拷贝就可以了。这时我们只需要进行一次判断然后执行对应的操作。就可以节省空间和时间了。

void* my_memmove(void* dest, const void* src, size_t count) {
	assert(dest && src);  	//判断指针不为空
	void* ret = dest;		//	保存目标空间的地址
	if (dest > src) {		//判断是目标空间地址是否大于源空间地址
		while (count--) {
			*((char*)dest + count) = *((char*)src + count);	//从后往前拷贝
		}
	}
	else {		//目标空间地址小于源空间地址
		while (count--) {
			*(char*)dest = *(char*)src;		//从前往后拷贝
		(char*)dest = (char*)dest + 1; 	
		(char*)src = (char*)src + 1;	  
		}
	}
	return ret; 	//实现链式访问
}

两个函数之间的差距就在重叠空间的拷贝,虽然现在在一些编译器下memcpy函数也可以实现重叠空间的拷贝,但是并不是全部编译器都可以实现。所以在编写代码的时候就需要严格得将两者分开,保证代码的可移植性。

memcmp 内存比较函数

memcmp 函数的使用可以对比strcmp函数,当空间1的数据小于空间2的数据,就返回下于0的数;两空间相等的话就返回0;当空间1的数据大于空间2的数据,就返回大于0的数。

memcmp 函数的定义

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

memcmp函数的模拟实现这里就不做讲解,可以参考strcmp的实现。


总结

本文仅仅简单得介绍了内存操作函数memcpy、memmove、memcmp,其中还有memcpy、memmove函数的模拟实现供大家参考,希望可以帮助到大家。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

内存操作函数【快速了解内存函数的作用和实现】 的相关文章

随机推荐

  • 深度学习经典网络解析图像分类篇(一):LeNet-5

    深度学习经典网络解析图像分类篇 一 LeNet 5 1 背景介绍 2 LeNet 5网络架构 2 1输入层 2 2第一层 卷积层C1 2 3第二层 池化层S2 下采样 2 3第三层 卷积层C3 第四层 池化层S4 第五层 卷积层C5 第六层
  • 无序(未排序)数组二分查找

    二分查找也称折半查找 Binary Search 它是一种效率较高的查找方法 但是 折半查找要求线性表必须采用顺序存储结构 而且表中元素按关键字有序排列 但是对于无序数组 我们可以先排序在二分 但还有一种技巧就是结合快排的思想 即每次选择一
  • 电脑提示msvcp110.dll是什么意思?msvcp110.dll丢失修复办法分享

    当我们使用电脑时 有时候会出现一些错误提示 其中就包括了 msvcp110 dll 丢失 的提示 那么 这个提示是什么意思呢 电脑提示找不到msvcr110 dll怎么办 我们在使用电脑的时候 总是会遇到很多的电脑难题 当我们在遇到了缺少m
  • CMake中while/continue/break的使用

    CMake中的while命令用于在条件为true时评估 evaluate 一组命令 其格式如下 while
  • 使用Numpy创建三维矩阵

    1 创建语句 创建形式有两种 1 随机数形式 np random random x y z 2 0或1形式 np ones x y z np zeros x y z 2 x y z 的含义 如果把x y z想做一个空间直角坐标系 那么x就相
  • SpringCloud环境搭建及入门案例

    技术选型 Maven 3 8 4 SpringBoot 2 7 8 SpringCloud 2021 0 4 SpringCloudAlibaba 2022 0 1 0 Nacos 2 1 1 Sentinel 1 8 5 模块设计 父工程
  • iptables上如何封IP

    一 封单个IP 1 封锁单个ip iptables I INPUT s IP j DROP root node1 iptables I INPUT s 192 168 1 11 j DROP root node1 iptables L Ch
  • 内网渗透之AccessToken窃取与利用

    文章目录 令牌 Token AccessToken的窃取与利用 1 程序 incognito exe 2 MSF下的incognito模块 3 Invoke TokenManipulation ps1脚本 MSF实战假冒令牌提权 令牌 To
  • MES管理系统的哪些优势对企业帮助比较大

    随着全球制造业的快速发展 MES制造执行系统已成为企业生产管理的重要工具 MES管理系统解决方案集成了企业生产流程中的各个环节 包括计划 调度 质量 设备等 为企业提供了全面的生产管理解决方案 制造企业MES系统的优势颇多 其中对企业帮助比
  • Nginx反向代理配置

    首先配置反向代理前已经要把之前配置过的伪静态删除掉 不然保存的时候报错以下是反向代理的完整配置 请注意其中的端口号 8000 当前这个端口号就是 config swoole php文件中的server port配置中的端口号 locatio
  • Admin监控&Sleuth链路追踪 &skywalking链路追踪

    Admin监控 Sleuth链路追踪 skywalking Sleuth Zipkin 一 Sleuth Zipkin介绍 二 搭建环境 三 Sleuth入门操作 四 Zipkin搭建及操作 五 RabbitMQ方式发送信息 六 Elast
  • Net跨平台UI框架Avalonia入门-DataGrid的使用

    Avalonia中的DataGrid的使用 DataGrid 数据表格是客户端UI中很重要的一个控件 Avalonia中的DataGrid是单独一个包Avalonia Controls DataGrid 要使用DataGrid 需要另外在N
  • 3559 编译gdb-7.9

    1 安装ncurses 6 0 这个在3559 sdk中有 可以直接使用 configure with shared without debug without ada enable overwrite 2 编译gdb configure
  • 1007. 素数对猜想 (20)

    让我们定义 dn 为 dn pn 1 pn 其中 pi 是第i个素数 显然有 d1 1 且对于n gt 1有 dn 是偶数 素数对 猜想 认为 存在无穷多对相邻且差为2的素数 现给定任意正整数N lt 105 请计算不超过N的满足猜想的素数
  • pragma指令简介

    在编写程序的时候 我们经常要用到 pragma指令来设定编译器的状态或者是指示编译器完成一些特定的动作 下面介绍了一下该指令的一些常用参数 希望对大家有所帮助 一 message 参数 message 它能够在编译信息输出窗 口中输出相应的
  • java包装类

    1 概述 将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据 常用操作方法之一 用于基本数据类型与字符串之间的转换 2 Integer 2 1构造方法 2 1 1 public Integer int number
  • 12 C++的多态

    文章目录 一 多态的概念 1 1 多态的构成条件 二 虚函数 2 1 虚函数的重写 2 2 虚函数重写的例外 协变 父类与子类虚函数返回值类型不同 析构函数的重写 基类与派生类析构函数的名字不同 三 C 11 override和final
  • Truffle测试框架

    Truffle测试框架 Truffle 有一个标准的自动化测试框架 让你可以非常方便地测试您的合约 这个框架允许您以两种不同的方式编写简单可控的测试 1 在 JavaScript中 用于执行来自外部世界的合约 就像您的应用程序一样 2 在
  • keil5点击调试提示SarmCM3.dll文件缺少问题

    这里继续分享一个在keil5点击Debug调试时候 提示缺少SarmCM3 dll文件问题 如图所示 这里提示我缺少一个SarmCM3 dll文件 因此我们只需要从网上找一个相应的文件加到BIN文件夹下即可 文件如图所示 解决方法 下载Sa
  • 内存操作函数【快速了解内存函数的作用和实现】

    文章目录 前言 内存操作函数的共性 memcpy 函数的定义 memmove 函数的定义 memcmp 函数的定义 函数的共性 memcpy 函数 内存拷贝函数 memcpy函数的定义 模拟实现memcpy 函数 memmove 函数 me