【C语言进阶】内存函数

天生我材必有用,千金散尽还复来。                                  ——李白

 

目录

前言

一.memcpy函数

​1.实现memcpy函数

2.模拟实现memcpy函数

二.memmove函数

1.实现memmove函数

2.模拟实现memmove函数 

三.memcpy函数和memmove函数的关系 

四.memcmp函数

1.实现memcmp函数

2.模拟实现memcmp函数 

五.memset函数 


前言

上次我们学习了字符串函数:strcpy,strcat,strcmp等等字符串函数,顾名思义这些字符串函数只能对字符串进行一系列的操作,而不能对整型,浮点型之类的内容进行操作。

今天我们就要学习内存函数:memcpy,memmove,memcmp等等内存函数。前缀mem就是英文里面的memory单词的意思,而memory在计算机里面理解为内存,所以这些函数是对内存进行操作,不会被类型所限制,可以操作各种各样的类型。

一.memcpy函数

 void *memcpy( void *dest, const void *src, size_t count ),这里为什么要用void*的指针呢?

因为这是一个内存函数,我们可以操作各种的数据类型,void*的指针可以接收任何类型的指针。在要使用的时候,只需要将void*强制类型转换即可达到目的。

 1.实现memcpy函数

#include<stdio.h>
#include<string.h>//内存函数的头文件
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 20);//20也就是20个字节,即拷贝5个整型
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

2.模拟实现memcpy函数

void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* start = dest;
	while (num)//一共20个字节
	{
		*(char*)dest = *(char*)src;//一个一个字节的进行拷贝
		dest = (char*)dest + 1;
		src = (char*)src + 1;
		num--;//直到num为0个字节时,即拷贝结束
	}
	return start;
}
int main()
{
   int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
   int arr2[10] = { 0 };
   my_memcpy(arr2, arr1, 20);//20也就是20个字节,即拷贝5个整型
   int i = 0;
   for (i = 0; i < 5; i++)
   {
	printf("%d ", arr2[i]);
   }
   return 0;
}


 

当我们要把自己数组的内容给拷贝的自己的数组内容上会发生什么?

void* my_memcpy(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* start = dest;
	while (num)//一共20个字节
	{
		*(char*)dest = *(char*)src;//一个一个字节的进行拷贝
		dest = (char*)dest + 1;
		src = (char*)src + 1;
		num--;//直到num为0个字节时,即拷贝结束
	}
	return start;
}
int main()
{
   int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
   my_memcpy(arr+2, arr, 20);//在一个数组里面操作
   int i = 0;
   for (i = 0; i < 10; i++)
   {
	printf("%d ", arr[i]);
   }
   return 0;
}

我们的目的是arr数组里面的3 4 5 6 7改为1 2 3 4 5,结果应该是1 2 1 2 3 4 5 8 9 10。结果是什么呢?让我们一起来看看。

结果为什么是这样呢?我们不妨通过画图来理解一下,在做题时,画图时非常重要的。 

这里就是有重叠的部分,在对于有重叠的部分 ,我们使用memmove函数。

二.memmove函数

1.实现memmove函数

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

2.模拟实现memmove函数 

void* my_memmove(void* dest, void* src, size_t num)
{
	assert(dest && src);
	void* start = dest;
	while (num)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
		num--;
	}
	return start;
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr+2, arr, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

为什么又是这样,到这里可能人都要被气成sb,但是我们要心平气和,继续我们的画图来好好的来理解一下。

 

正确的代码: 

void* my_memmove(void* dest, void* src, size_t num)
{
	assert(dest && src);
	void* start = dest;
	if(dest>src)
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	else
	{
		while (num)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
			num--;
		}
	}
	return start;
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr+2, arr, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

三.memcpy函数和memmove函数的关系 

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

这里可以看出数组即使有重叠的部分 ,但是memcpy函数一样的可以实现和memmove函数一样的功能。我们可以这样理解:其实memcpy函数是memmove函数的一个子函数。

在vs平台上memcpy函数和memmove的功能一模一样,但是并不保证在其他平台上面两个函数的功能是一样的。

总结:在有重叠部分的时候都用memmove函数。没重叠部分的,两个函数用谁都行。

四.memcmp函数

1.实现memcmp函数

memcmp函数也是一个字节一个字节的进行比较。同样和strcmp函数一样,最后比较的是ASCll码值。

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 1,2,3,4,5,7 };
	int ret=memcmp(arr1, arr2, 20);
	printf("%d\n", ret);
	return 0;
}


 

比较21字节会是怎么样呢? 

int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 1,2,3,4,5,7 };
	int ret=memcmp(arr1, arr2, 21);//比较21字节会是怎么样呢?
	//前20个字节都相等,这是毋庸置疑的的
	//6的小端字节序:06 00 00 00
	//7的小端字节序:07 00 00 00
	//很明显7的第一个字节大于6,即arr2大于arr1,返回-1
	printf("%d\n", ret);
	return 0;
}


 

2.模拟实现memcmp函数 

模拟实现memcmp函数和模拟实现strcmp函数是非常相似的。

int my_memcmp(const void* buf1, const void* buf2, size_t num)
{
	assert(buf1 && buf2);
	size_t m = num;
	while (num--)
	{
		if (*(char*)buf1 == *((char*)buf2))
		{
			buf1 = (char*)buf1 + 1;
			buf2 = (char*)buf2 + 1;
		}
		else
			return (*(char*)buf1 - *((char*)buf2));
	}
	return 0;//退出循环都没有return,那么就说明两个是相等的。
}
int main()
{
	int arr1[10] = { 1,2,4,4,5,6,7,8,9,10 };
	int arr2[10] = { 1,2,5 };
	int ret = my_memcmp(arr1, arr2, 9);//比较9个字节
	if (ret == -1)
	{
		printf("arr1小于arr2\n");
	}
	else if (ret == 1)
	{
		printf("arr1大于arr2\n");
	}
	else
		printf("arr1和arr2相等\n");
	return 0;
}

五.memset函数 

void *memset(void *str, int c, size_t n)
//str -- 指向要填充的内存块。
//c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
//n -- 要被设置为该值的字符数。

代码实现:

int main()
{
	char arr[20] = "hello world";
	memset(arr, '*', 5);//将arr的前五个字节改为*
	printf("%s\n", arr);
}


 

如果我们要对整数进行操作呢?

int main()
{
	int arr[10] = { 1,2,3,4,5 };
	memset(arr, 1, 8);//操作8个字节
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

这里为什么为得到这么奇怪的数字呢?

注意:memset是一个一个字节的进行操作,而int是4个字节为一个数字。 

如:1的小端字节序是 01 00 00 00,然后一个一个字节的改为1,最后就成了 01 01 01 01

16进制的01010101就是16843009。

所以memset不能随便用,有可能会带来不一样的结果。要根据实际情况来使用。

感谢老铁们的支持。 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据大放送之历史影像下载

一、前言作为一个怀旧的人&#xff0c;那么一定会对生活过的地方的历史照片感兴趣。只是因为年代久远&#xff0c;很多老照片都没有保存下来。而且受限于几十年前的技术条件&#xff0c;你很难获取到你家乡城市的高清全貌图片&#xff0c;也无法从空中俯瞰祖辈们和你曾经生活的…

SpringCloud微服务技术栈.黑马跟学(三)

SpringCloud微服务技术栈.黑马跟学 三今日目标1.初识Docker1.1.什么是Docker1.1.1.应用部署的环境问题1.1.2.Docker解决依赖兼容问题1.1.3.Docker解决操作系统环境差异1.1.4.小结1.2.Docker和虚拟机的区别1.3.Docker架构1.3.1.镜像和容器1.3.2.DockerHub1.3.3.Docker架构1.3.4.…

Python04 数据序列-字符串

Python04 数据序列-字符串 4.1 字符串概念 字符串是 Python 中最常用的数据类型。我们可以使用引号( ’ 或 " )来创建字符串。 格式&#xff1a; 变量名 数据 / "数据" / """ 数据 """案例&#xff1a; a hello world b &q…

动态规划-基础(斐波那契数、爬楼梯、使用最小花费爬楼梯、不同路径、不同路径II、整数拆分、不同的二叉搜索树)

动态规划&#xff0c;英文&#xff1a;Dynamic Programming&#xff0c;简称DP&#xff0c;如果某一问题有很多重叠子问题&#xff0c;使用动态规划是最有效的。所以动态规划中每一个状态一定是由上一个状态推导出来的。动态规划问题&#xff0c;五步走&#xff1a;状态定义&am…

Java学习星球,Java学习路线

目录一、Java学习路线二、学习计划三、为何会有Java学习星球&#xff1f;四、加入星球后&#xff0c;你可以得到什么&#xff1f;五、如何加入Java学习星球&#xff1f;六、打卡挑战大家好&#xff0c;我是哪吒&#xff0c;一个靠着热情攀登至C站巅峰的中年男子&#xff0c;CSD…

【数据结构】第三站:单链表

目录 一、顺序表的缺陷 二、链表 1.链表的概念以及结构 2.链表的分类 3.单链表的逻辑结构与物理结构 三、单链表的实现 1.单链表的定义 2.单链表的接口定义 3.单链表的接口实现 四、单链表的实现完整代码 一、顺序表的缺陷 在上一篇文章中&#xff0c;我们了解了顺序…

C语言实现单链表(超多配图,这下不得不学会单链表了)

目录 一&#xff1a;什么是链表&#xff1f; 二&#xff1a;创建源文件和头文件 (1)头文件 (2)源文件 三&#xff1a;实参和形参 四&#xff1a;一步步实现单向链表 &#xff08;1&#xff09;建立一个头指针并置空 &#xff08;2&#xff09;打印链表&#xff0c;便于…

人脸活体检测系统(Python+YOLOv5深度学习模型+清新界面)

摘要&#xff1a;人脸活体检测系统利用视觉方法检测人脸活体对象&#xff0c;区分常见虚假人脸&#xff0c;以便后续人脸识别&#xff0c;提供系统界面记录活体与虚假人脸检测结果。本文详细介绍基于YOLOv5深度学习技术的人脸活体检测系统&#xff0c;在介绍算法原理的同时&…

echart图表之highcharts

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、HighCharts是什么&#xff1f;二、使用步骤1.引入库2.前端代码3.展现结果4.后台自动截图总结前言 提示&#xff1a;这里可以添加本文要记录的大概内容&…

vue2前端实现html导出pdf功能

1. 功能实现方案 1.html转换成canvas后生成图片导出pdf&#xff08;本文选用&#xff09; html转canvas插件&#xff1a;html2canvas是一款将HTML代码转换成Canvas的插件&#xff1b;canvas生成pdf&#xff1a;jsPDF是一个使用Javascript语言生成PDF的开源库 2.HTML代码转出…

FPGA纯verilog实现RIFFA的PCIE通信,提供工程源码和软件驱动

目录1、前言2、RIFFA简介RIFFA概述RIFFA架构RIFFA驱动3、vivado工程详解4、上板调试验证并演示5、福利&#xff1a;工程代码的获取1、前言 PCIE是目前速率很高的外部板卡与CPU通信的方案之一&#xff0c;广泛应用于电脑主板与外部板卡的通讯&#xff0c;PCIE协议极其复杂&…

Python3实现AI版贪吃蛇

导语利用Python简单地实现AI版的贪吃蛇。。。just for fun...没有用深度学习。。。算法是由一个叫Hawstein的人在好多好多年以前提出&#xff0c;感觉很有趣&#xff0c;就花了点时间复现了一下他的想法。。。至于效果。。。看脸。。。真的只是觉得他的想法很有趣&#xff0c;仅…

AI_Papers周刊:第六期

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 2023.03.13—2023.03.19 文摘词云 Top Papers Subjects: cs.CL 1.UPRISE: Universal Prompt Retrieval for Improving Zero-Shot Evaluation 标题&#xff1a;UPRISE&#xff1a;改进零样本评估…

Java面向对象:接口的学习

本文介绍了Java中接口的基本语法, 什么是接口, java中的接口 语法规则, 接口的使用,接口的特性,如何实现多个接口,接口间的继承,以及抽象类和接口的区别 Java接口的学习一.接口的概念二.Java中的接口1.接口语法规则2.接口的使用3.接口的特性4.实现多个接口5.接口间的继承三.抽象…

Vue学习 -- 如何用Axios发送请求(get post)Promise对象 跨域请求问题

什么是Axios Vue本身是不支持发送axios请求&#xff0c;需要使用第三方插件&#xff0c;这里推荐使用Axios&#xff0c;Axios是基于promise的HTTP库&#xff1b;它会从浏览器中创建XMLHttpRequset对象。 安装Axios npm install axios -S下载后把axios.js文件复制进项目目录 …

QT串口助手开发3串口开发

系列文章目录 QT串口助手开发3串口开发 QT串口助手开发3系列文章目录一、UI界面程序的编写二、发送框程序编写一、UI界面程序的编写 根据上文的未解决问题&#xff1a;我们打开串口按钮打开后只能选择关闭串口&#xff0c;所以这个是循环的过程 上文链接 所以按钮对应的槽函数…

VR全景城市,用720全景树立城市形象,打造3D可视化智慧城市

随着城市化进程的加速&#xff0c;城市之间的竞争也日益激烈。城市管理者们需要寻求新的方式来提升城市的品牌形象和吸引力。在这个过程中&#xff0c;VR全景营销为城市提供了一种全新的营销手段&#xff0c;可以帮助提升城市的价值和吸引力。一、城市宣传新方式VR全景营销是一…

《Linux的权限》

本文主要对linux的一些基本权限进行讲解 文章目录前言Linux权限&#xff08;1&#xff09;权限的概念&#xff08;2&#xff09;linux下用户分类(root,普通)(3)linux的文件属性文件属性的分类文件权限修改文件权限1、chmod2、chown和chgrp3、fiile权限的三个重要的问题第一个问…

考研408每周一题(2019 41)

2019年(单链表&#xff09; 41.(13分)设线性表L(a1,a2,a3,...,a(n-2),a(n-1),an)采用带头结点的单链表保存&#xff0c;链表中的结点定义如下&#xff1a; typedef struct node {int data;struct node *next; } NODE; 请设计一个空间复杂度为O(1)且时间上尽可能高效的算法&…

嵌入式学习笔记——STM32的时钟树

时钟树前言时钟树时钟分类时钟树框图LSI与LSEHSI、HSE与PLL系统时钟的产生举例AHB、APBx的时钟配置时钟树相关寄存器介绍1.时钟控制寄存器&#xff08;RCC_CR&#xff09;2.RCC PLL 配置寄存器 (RCC_PLLCFGR)3.RCC 时钟配置寄存器 (RCC_CFGR)4.RCC 时钟中断寄存器 (RCC_CIR)修改…
最新文章