浅谈内存函数以及模拟实现

news2024/9/25 22:39:37

1.memcpy

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

函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
这个函数在遇到 '\0' 的时候并不会停下来。
如果source和destination有任何的重叠,复制的结果都是未定义的。

 

 接下来我们使用一下这个函数:

#include<string.h>
int main()
{
	int arr1[10] = { 0 };
	int arr2[] = { 1,2,3,4,5 };
	memcpy(arr1, arr2, 20);
	return 0;
}

 经过调试之后可以发现arr1里面存放了1,2,3,4,5,这个就是memcpy的基本用法。


2.模拟实现memcpy

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<string.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	while (num)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
		num--;
	}
}
int main()
{
	int arr1[10] = { 0 };
	int arr2[] = { 1,2,3,4,5 };
	my_memcpy(arr1, arr2, 20);
	return 0;
}

src里面的内容是不会被改变的,所以使用const限制一下。num是拷贝的字节数,我们每次拷贝一个字节。先使用while循环,循环num次,每次num--,dest和src是void*的指针,我们强制类型转换为char*的指针,然后解引用,将src赋给dest,dest和src这时就应该往后走一个字节,因为强制类型转换是临时的,所以还是需要强制类型转换为char*,然后+1。

当我们想把1,2,3,4,5放到3,4,5,6,7的位置上时就会出现问题,当空间不重叠内存的时候使用memcpy是可以的,像这种不重叠内存的拷贝需要使用memmove。

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	memcpy(arr + 2, arr, 20);
	return 0;
}

 3.memmove

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

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	memcpy(arr + 2, arr, 20);
	return 0;
}

 使用memmove的话就能很好的解决上面的问题。


4.模拟实现memmove

我们先来想一下,如果有一个数组:

int arr[]={1,2,3,4,5,6,7,8,9,10};

假如我们要把1,2,3,4,5拷贝到3,4,5,6,7这个位置上去,使得数组变成:

int arr[]={1,2,1,2,3,4,5,8,9,10};

那我们就需要先将5放在7的位置上,4放在6的位置上,以此类推,才能达到效果,也就是从后向前拷贝。

如果我们要把3,4,5,6,7拷贝到1,2,3,4,5这个位置上,就要先将3放到1的位置上,以此类推,也就是从前往后拷贝。

所以说拷贝的方式会根据需求而改变。

那么什么时候从前往后拷贝,什么时候从后往前拷贝呢?

还是用一个数组举例:

int arr[]={1,2,3,4,5,6,7,8,9,10};

如果dest这块空间在src这块空间的左边且重叠,也就是要把高地址的数据拷贝到低地址处,就需要从前往后拷贝。

如果dest这块空间在src这块空间的右边且重叠,也就是要把低地址的数据拷贝到高地址处,就需要从后往前拷贝。

如果dest这块空间和src这块空间不重叠,不管从前往后还是从后往前都是可以的,当然是在空间充足的情况下,不能越界。


 一开始我们还是需要保存起始位置的地址,用作返回值。使用if判断dest是否小于src,如果小于则进入for循环,循环sz次,这里的方法是跟上面的memcpy一样的。当dest>src时,我们使用while循环比较方便,因为我们从后向前拷贝是先将后面的数据开始,所以当我们将条件设置成sz--时,由于是后置--,也是循环sz次,但是*((char*)src + sz)就刚好能够拿出最后一个数据拷贝到*((char*)dest + sz),当然使用for循环也是可以的。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memmove(void* dest,const void* src,size_t sz)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src)//从前向后
	{
		for (int i = 0; i < sz; i++)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest+1;
			src = (char*)src + 1;
		}
	}
	else//从后向前
	{
		while (sz--)
		{
			*((char*)dest + sz) = *((char*)src + sz);
		}
	}
	return ret;
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr, arr + 2, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

 


5.memset

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

 这个函数就是将ptr指向的前num个字节的数据设置成指定的值(value),再把起始位置返回。

下面是memset的使用: 

int main()
{
	char arr[] = "hello world";
	memset(arr + 6, 'x', 3);
	printf("%s\n", arr);
	return 0;
}

 但是要注意的是num的单位是字节。如果我们想要把这个数组的内容设置成10个1,像下面这样就已经出错了,这样是把每个字节都设置成1,而不是整型。

int main()
{
	int arr[10] = { 0 };
	memset(arr, 1, 40);
	return 0;
}


6.memcmp

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

 memcmp这个函数就是比较两块空间的前num个字节的内容,如果一样则返回0,小于则返回<0,大于则返回>0。需要注意的是在比较时也是一对字节进行比较,和strcmp的区别就是strcmp是进行字符的比较,而memcmp是进行内存块的比较。

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[] = { 1,2,3,4 };
	int ret=memcmp(arr1, arr2, 16);
	printf("%d ", ret);
	return 0;
}


今天的分享到这里就结束啦!谢谢老铁们的阅读,让我们下期再见。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1074247.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小白学习笔记—网络安全/黑客技术

作为一个合格的网络安全工程师&#xff0c;应该做到攻守兼备&#xff0c;毕竟知己知彼&#xff0c;才能百战百胜。 谈起黑客&#xff0c;可能各位都会想到&#xff1a;盗号&#xff0c;其实不尽然&#xff1b;黑客是一群喜爱研究技术的群体&#xff0c;在黑客圈中&#xff0c;一…

【HomeKit】HAT User Manual教程

前言&#xff1a;这篇文章是对于苹果协议文件《HomeKit Accessory Tester (HAT) User Manual》的学习&#xff0c;即 HomeKit配件测试仪(HAT) 用户手册&#xff0c;该版本是第11次修订 第一章 概述 本文档介绍了Apple HomeKit配件测试仪(HAT)的配置和使用方法。HAT是一个Mac应…

家政系统开发,家政保洁维修预约小程序开发;

家政系统是家政行业的专业管理系统软件&#xff0c;功能涉及到家政公司运营的方方面面&#xff0c;包括&#xff1a;推广、营销、管理、培训、周边服务等等&#xff1b; 家政系统功能介绍&#xff1a; 系统集成分销客户裂变、微信推广、团购引流、热文海报推广、短视频引流、搜…

Camera metadata

目录 背景 CameraMetadata基本概念 Google Metadata Google—Metadata结构 官方注释 Aandroid API cameraMetadata头部 : struct camera_metadata camera_metadata_buffer_entry struct camera_metadata_entry data区为什么是一个联合体&#xff1f; camera metadat…

什么是Fetch API?与传统的AJAX相比,有什么优势?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

3分钟学会批量查询快递秘籍

随着网购的普及&#xff0c;我们经常需要查询快递来了解自己的包裹状态。然而&#xff0c;如果一个个手动查询&#xff0c;不仅费时而且麻烦。这时候&#xff0c;一款能够批量查询快递的软件就变得尤为重要。今天&#xff0c;我将向大家介绍一款名为“固乔快递查询助手”的软件…

Linux知识点 -- 网络基础 -- 数据链路层

Linux知识点 – 网络基础 – 数据链路层 文章目录 Linux知识点 -- 网络基础 -- 数据链路层一、数据链路层1.以太网2.以太网帧格式3.重谈局域网原理4.MAC地址5.MTU6.查看硬件地址和MTU的命令7.ARP协议 二、其他重要协议或技术1.DNS&#xff08;Domain Name System&#xff09;2.…

2008-2020年中国区域二氧化氮产品

简介&#xff1a; 针对OMI 2008-2020年数据中因行异常或者云造成缺失的对流程NO2数据进行填补&#xff0c;利用面积权重法将OMI和GOME数据统一重采样至0.25度的空间分辨率。前言 – 人工智能教程 二氧化氮&#xff08;Nitrogen Dioxide&#xff0c;简称NO2&#xff09;是一种…

Java每日笔试题错题分析(1)

Java每日笔试题错题分析&#xff08;1&#xff09; 一、错题知识点前瞻第26题第29题第34题第41题第50题 二、错题展示及其解析第26题第29题第34题第41题第50题 一、错题知识点前瞻 第26题 多个catch块中子类异常放在前面&#xff0c;父类异常放在后面&#xff0c;否则会产生编…

ssm173基于SSM的养老院老人健康监护平台设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

保姆级微服务部署教程

大家好&#xff0c;我是鱼皮。 项目上线是每位学编程同学必须掌握的基本技能。之前我已经给大家分享过很多种上线单体项目的方法了&#xff0c;今天再出一期微服务项目的部署教程&#xff0c;用一种最简单的方法&#xff0c;带大家轻松部署微服务项目。 开始之前&#xff0c;…

《安富莱嵌入式周报》第324期:单对以太网技术实战,IROS2023迪士尼逼真机器人展示,数百万模具CAD文件下载,闭环步进电机驱动器,CANopen全解析

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 更新一期视频教程&#xff1a; 第8期ThreadX视频教程&#xff1a;应用实战&#xff0c;将裸机工程移植到RTOS的任务划分…

自助建站系统,一建建站系统api版,自动建站

安装推荐php7.2或7.2以下都行 可使用虚拟主机或者服务器进行搭建。 分站进入网站后台 域名/admin 初始账号123456qq.com密码123456 找到后台的网站设置 将主站域名及你在主站的通信secretId和通信secretKey填进去。 即可正常使用 通信secretId和通信secretKey在主站的【账号…

【Proteus仿真】【STM32单片机】病床呼叫系统设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真STM32单片机控制器&#xff0c;使用LCD1602液晶、按键、蜂鸣器LED、双机通信等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示开机界面&#xff0c;当从机病床按键按…

ExoPlayer架构详解与源码分析(4)——整体架构

系列文章目录 ExoPlayer架构详解与源码分析&#xff08;1&#xff09;——前言 ExoPlayer架构详解与源码分析&#xff08;2&#xff09;——Player ExoPlayer架构详解与源码分析&#xff08;3&#xff09;——Timeline ExoPlayer架构详解与源码分析&#xff08;4&#xff09;—…

0-1背包理论基础详解

0-1背包问题&#xff1a;有 n 种物品&#xff0c;每种物品只有1个&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 图片来自&#xff1a;代码随想录 0-1背包问题举例&#xff1a; 题目描述&#xff1a; 使用二维dp数组解决背包问题 动规五部曲&#xff1a; dp[i][j…

智能工厂MES系统,终端设备支持手机、PDA、工业平板、PC

一、开源项目简介 源计划智能工厂MES系统(开源版) 功能包括销售管理&#xff0c;仓库管理&#xff0c;生产管理&#xff0c;质量管理&#xff0c;设备管理&#xff0c;条码追溯&#xff0c;财务管理&#xff0c;系统集成&#xff0c;移动端APP。 二、开源协议 使用GPL-3.0开…

【python海洋专题十四】读取多个盐度nc数据画盐度季节变化图

本期内容 读取多个盐度文件&#xff1b;拼接数据在画盐度的季节分布图Part01. 使用数据 IAP 网格盐度数据集 数据详细介绍&#xff1a; 见文件附件&#xff1a; pages/file/dl?fid378649712527544320 全球温盐格点数据.pdf IAP_Global_ocean_gridded_product.pdf 全球温…

Android多线程学习:线程池(一)

一、概念 线程池&#xff1a;创建并维护一定数量的空闲线程&#xff0c;当有需要执行的任务&#xff0c;就交付给线程池中的一个线程&#xff0c;任务执行结束后&#xff0c;该线程也不会死亡&#xff0c;而是回到线程池中重新变为空闲状态。 线程池优点&#xff1a; 1、重用…

Linux系列---【查看mac地址】

查看mac地址命令 查看所有网卡命令 nmcli connection show 查看物理网卡mac地址 ifconfig 删除网卡 nmcli connection delete virbr0 禁用libvirtd.service systemctl disable libvirtd.service 启用libvirtd.service systemctl enable libvirtd.service