C语言-------内存函数

news2024/12/30 2:45:32

前面向大家介绍了C语言中的字符函数和字符串函数,今天再向大家介绍一下类似的函数————

C语言中的内存函数。

1. memcpy函数的使用和模拟实现

memcoy函数是一种通过内存来复制内容的一种函数,以字节为基本单位进行,斌并且是一个可以复制任何类型数据的函数。

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

上面代码就是memcpy函数的一个基本形式。 

用法解释:destination是一个指向目标空间的 void* 类型的指针,source是一个指向源空间(提供复制的内容的对象)的指针。num是一个无符号整形的参数,单位是字节。

意思就是从source指向的位置开始向后复制num个字节的内容复制destination指向的位置。

使用时注意事项:

1. memcpy函数进行内容的复制时,遇到源空间的 '\0' 不会停止。

2. memcpy函数进行内容复制时的基本单位是字节

3. memcpy函数使用时,最好不要涉及到目标空间和源空间共同覆盖的空间,否则复制的结果都是未定义的。

老样子,上代码。

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[5] = { 0 };
	printf("复制前arr2数组为:");
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}
	printf("\n");
	memcpy(arr2, arr1, 3 * sizeof(arr1[0]));
	//3*sizeof(arr1[0])是指将从arr1开始复制直到到达12个字节
	printf("复制后arr2数组为:");
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;

}

memcpy函数的模拟实现

void my_memcpy(void* dest, const void* src, int num) //设置成void* 型指针是为了接受任何类型的数据
{
	while (num--)
	{
		*(char*)dest = *(char*)src;
		//因为void*指针无法直接进行解引用,我们将其转换成char*型的
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
}
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[10] = { 0 };
	my_memcpy(arr2, arr1, 20);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

以上就是memcpy函数的模拟实现

有人看了代码就疑惑了,为什么偏偏实现函数功能是将指针强制转换成char*的呢?

其实就是为了方便操作

本质上是将要复制的内容转换为一个一个字节复制过去,而char*型的指针一次就只能操作一个字节,就实现了通过一个一个字节来复制内容。 

运行如下图

实现模拟之后,我们再来解释一下为什么操作的空间最好不要有重叠。

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

 通过画图我们知道,按照上面代码操作,4和5的空间是共同覆盖的,所以当进行到复制半路的途中,4和5就会被改为1和2了,然而4和5也是后面要复制的内容,但是4和5已经提前被改为1和2了,所以后面的复制操作也是会有影响的。

运行代码

但是这种效果是通过我们模拟实现的。

如果我们真使用上memcpy函数时,memcpy函数还是会正常实现复制的。

这说明VS中memcpy函数已经具备了处理空间重叠的问题。但我们如果以后遇到的空间是重叠的,最好不要使用memcpy函数。

所以C语言就为我们提供了一个处理空间重叠的函数------memmove函数

2. memmove函数的使用和模拟实现 

其实memmove函数和memcpy函数的用法是差不多的,不同点在于memmove函数是专门设计来处理目标空间和源空间重叠的问题的。

需要注意的是:memmove函数处理的基本单位也是字节。

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

上代码

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

 

运行代码发现,memmove函数在处理目标空间和源空间重叠时,是可以正常将源空间的内容复制到目标空间的。

所以每当我们在复制内容时,遇到目标空间和源空间重叠的问题时,必须使用memmove函数。

memmove函数的模拟实现

在模拟实现memmove函数遇到的情况比较多也比较复杂。我们 一 一 来分析。

第一种情况

如上图,当dest和src指向的空间没有重叠时,我们只需要把src里面要复制的内容从前向后或者从后向前拷贝到目标空间中去。

第二种情况

如图,当src指向的空间于dest指向的空间有重叠部分时,并且src在dest的左边时,我们依次将src指向的内容从前向后拷贝到dest指向的空间时,我们会发现这样拷贝时,我们会将后面要拷贝的4和5变成了1和2,这样要拷贝4和5时就无法拷贝了,因为4和5应经提前被替换成1和2了,已经没有4和5了。

 所以这时候我们要改变一下,将src里面的内容从后向前拷贝。

如上图,当我们将src指向的内容依次从后向前拷贝到dest指向的目标空间时,我们会发现这样就能正常复制内容。

第3种情况

 

这时我们发现当空间有重叠时,并且src在dest的右边时,我们将src里面的内容依次从前向后拷贝的dest指向的空间时,是可以正常运行的。

总结: 

1.当 src在  1  区域时,也就是在dest的左边时,我们将src指向的内容从后向前拷贝。(src<dest)

2.当src在  2 和 3 区域时,也就是在dest的右边时,我们将src指向的内容从前向后拷贝。(src>dest)

代码实现

void my_memmove(void* dest, void* src, int num)
{
	if (src > dest)
	{
		//从前向后拷贝
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src+1;
		}
	}
	else
	{
		while (num--)
		{
			//num- -的同时,也样dest和src向后退了 
			*((char*)dest + num) = *((char*)src + num);
		}
	}
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	my_memmove(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

运行代码

 

3.memset函数的使用

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

memset函数是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。

解释memset的3个参数

1.ptr 是一个void* 类型的指针,其指向的是被修改内容空间的起始位置。

2.value是我们要设置的内容。

3.num 是表示从ptr指向的起始位置开始向后有多少个字节的内容需要改变。

老样子,上代码感受

int main()
{
	char arr[] = "hallo bit";
	memset(arr, 'x', 5 * sizeof(arr[0]));
	printf("%s", arr);
	return 0;
}

 

4.memcmp函数的使用

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

memcmp函数是用来比较ptr1指向的内容和ptr2指向的内容后num个字节的内容的大小。

       返回值              *ptr1-*ptr2
          >0             >0
           0                ==0
            <0               <0

我们还是直接通过代码感受一下

int main()
{
	char* str1 = "abcd";
	char* str2 = "abce";
	int ret=memcmp(str1, str2, 4);
	printf("%d\n", ret);
	if (ret > 0)
	{
		printf("str1>str2");
	}
	else if (ret < 0)
	{
		printf("str1<str2");
	}
	else
	{
		printf("str1==str2");
	}
}

运行代码 

 

完结,感谢大家的观看。 

 

 

 

 

 

 

 

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

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

相关文章

Git分支提交时自动大写 fatal: the remote end hung up unexpectedly

先说结论&#xff1a; 进入 .git/refs/heads目录&#xff0c;会看到Feature文件夹&#xff0c;重命名为feature即可。 表现&#xff1a; 通过终端命令创建的分支 git checkout -b feature/name 使用git push后自动变成了Feature/name 并且有时候在本地创建feature/1234567…

etcdctl配置

下载etcdctl压缩文件 wget https://github.com/etcd-io/etcd/releases/download/v3.5.0/etcd-v3.5.0-linux-amd64.tar.gztar -xvf etcd-v3.5.0-linux-amd64.tar.gzsudo mv ./etcd-v3.5.0-linux-amd64/etcdctl /usr/local/bin/ chmod x /usr/local/bin/etcdctl 配置etcdctl 配…

6.8物联网RK3399项目开发实录-驱动开发之RTC实时时钟的使用(wulianjishu666)

90款行业常用传感器单片机程序及资料【stm32,stc89c52,arduino适用】 链接&#xff1a;https://pan.baidu.com/s/1M3u8lcznKuXfN8NRoLYtTA?pwdc53f RTC 使用 简介 AIO-3399J 开发板上有 一个集成于 RK808 上的RTC(Real Time Clock)&#xff0c;主要功能有时钟&#xff0c…

OpenHarmony实战:轻量系统芯片移植准备

由于OpenHarmony工程需要在Linux环境下进行编译&#xff0c;此章节将指导厂商搭建OpenHarmony的编译环境、获取OpenHarmony源码&#xff0c;并且创建厂商工作目录完成厂商芯片的编译框架适配。 搭建编译环境 开展移植前请参考开发环境准备完成环境搭建工作。 获取源码 获取…

非关系型数据库-----------探索 Redis高可用 与持久化

目录 一、Redis 高可用 1.1什么是高可用 1.2Redis的高可用技术 二、 Redis 持久化 2.1持久化的功能 2.2Redis 提供两种方式进行持久化 三、Redis 持久化之----------RDB 3.1触发条件 3.1.1手动触发 3.1.2自动触发 3.1.3其他自动触发机制 3.2执行流程 3.3启动时加载…

服务器远程桌面连接不上怎么办?

随着互联网的发展和远程办公的兴起&#xff0c;服务器远程桌面连接成为了许多企业和个人不可或缺的工具。偶尔我们可能会碰到服务器远程桌面连接不上的情况&#xff0c;这时候我们需要找到解决办法&#xff0c;确保高效地远程访问服务器。 天联组网——突破远程连接障碍 在我们…

Linux网络编程二(TCP图解三次握手及四次挥手、TCP滑动窗口、MSS、TCP状态转换、多进程/多线程服务器实现)

文章目录 1、TCP三次握手(1) 第一次握手(2) 第二次握手(3) 第三次握手 2、TCP四次挥手(1) 一次挥手(2) 二次挥手(3) 三次挥手(4) 四次挥手 3、TCP滑动窗口4、TCP状态时序图5、多进程并发服务器6、多线程并发服务器 1、TCP三次握手 TCP三次握手(TCP three-way handshake)是TCP协…

玩转ChatGPT:Kimi测评(科研写作)

一、写在前面 ChatGPT作为一款领先的语言模型&#xff0c;其强大的语言理解和生成能力&#xff0c;让无数用户惊叹不已。然而&#xff0c;使用的高门槛往往让国内普通用户望而却步。 最近&#xff0c;一款由月之暗面科技有限公司开发的智能助手——Kimi&#xff0c;很火爆哦。…

Vue3_2024_7天【回顾上篇watch常见的后两种场景】完

随笔&#xff1a;这年头工作不好找咯&#xff0c;大家有学历提升的赶快了&#xff0c;还有外出人多注意身体&#xff0c;没错我在深圳这边阳了&#xff0c;真的绝啊&#xff0c;最尴尬的还给朋友传染了&#xff01;&#xff01;&#xff01; 之前三种的监听情况&#xff0c;监听…

java发送请求-cookie有关代码

在初始化后添加cookie的代码 用这个httpclients类调custom方法&#xff0c;进行代码定制化 找和cookie有关的方法&#xff0c;设置默认的cookie存储信息 入参是接口 将入参粘贴后找方法&#xff0c;用new实现这个接口 这个方法是无参空构造&#xff0c;可以使用 设置了cookie …

Java项目:86 springboot电影评论网站系统设计与实现

作者主页&#xff1a;源码空间codegym 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本电影评论网站管理员和用户。 管理员功能有个人中心&#xff0c;用户管理&#xff0c;电影类别管理&#xff0c;电影信息管理&#xff0c;留…

Linux系统---进程间通信与管道入门

顾得泉&#xff1a;个人主页 个人专栏&#xff1a;《Linux操作系统》 《C从入门到精通》 《LeedCode刷题》 键盘敲烂&#xff0c;年薪百万&#xff01; 一、进程间通信 1.进程间通信的目的 1.数据传输&#xff1a;一个进程需要把他的数据传给另外一个进程。 2.资源共享&…

idea开发 java web 酒店推荐系统bootstrap框架开发协同过滤算法web结构java编程计算机网页

一、源码特点 java 酒店推荐推荐系统是一套完善的完整信息系统&#xff0c;结合java web开发和bootstrap UI框架完成本系统 采用协同过滤算法进行推荐 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式…

Excel列匹配VLookUp功能使用

生活中很多关于excel多列数据进行匹配计算等场景,其中最常用的一个函数就是VLookUp了,下面直接上图: 得到结果如下: 得到结果如下: 注意: 1.在需要把计算完的数据粘贴到另一列或者另个sheet时,复制后,不要直接ctrlv粘贴,这样会把计算公式粘贴到对应的列.正确做法是:右键粘贴,选…

redis 的StringRedisTemplate

6.3 StringRedisTemplate 尽管JSON的序列化方式可以满足我们的需求&#xff0c;但依然存在一些问题&#xff0c;如图&#xff1a; 为了在反序列化时知道对象的类型&#xff0c;JSON序列化器会将类的class类型写入json结果中&#xff0c;存入Redis&#xff0c;会带来额外的内存…

Redis中的复制功能(三)

复制 服务器运行ID 除了复制偏移量和复制积压缓冲区之外&#xff0c;实现部分重同步还需要用到服务器运行ID(run ID): 1.每隔Redis服务器&#xff0c;不论主服务器还是从服务&#xff0c;都会有自己的运行ID2.运行ID在服务器启动时自动生成&#xff0c;由40个随机的十六进制…

基于kmeans的聚类微博舆情分析系统

第一章绪论 1.1研究背景 如今在我们的生活与生产的每个角落都可以见到数据与信息的身影。自从上十世纪八十年代的中后期开始&#xff0c;我们使用的互联网技术已经开始快速发展&#xff0c;近些年来云计算、大数据和物联网等与互联网有相领域的发展让互联网技术达到了史无前例…

浅谈iOS开发中的自动引用计数ARC

1.ARC是什么 我们知道&#xff0c;在C语言中&#xff0c;创建对象时必须手动分配和释放适量的内存。然而&#xff0c;在 Swift 中&#xff0c;当不再需要类实例时&#xff0c;ARC 会自动释放这些实例的内存。 Swift 使用 ARC 来跟踪和管理应用程序的内存&#xff0c;其主要是由…

Vue-Next-Admin:适配手机、平板、PC的开源后台管理模板

摘要&#xff1a;随着移动设备和PC的普及&#xff0c;为了满足不同设备的需求&#xff0c;开发一个能够自适应手机、平板和PC的后台管理系统变得至关重要。本文将介绍一个基于Vue3.x、Typescript、Vite、Element Plus等技术的开源模板库——Vue-Next-Admin&#xff0c;帮助开发…

rust项目组织结构和集成测试举例

概述 在学习rust的过程中&#xff0c;当项目结构略微复杂的时候&#xff0c;写集成测试的时候发现总是不能引用项目中的代码&#xff0c;导致编写测试用例失败。查阅了教程&#xff0c;一般举例都很简单。查阅了谷歌和百度以及ai&#xff0c;也没有找到满意的答案。这里记录一…