C语言快速入门之内存函数的使用和模拟实现

1.memcpy

它可以理解为memory + copy的组合,memory有记忆的意思,这里指的是内存,copy是拷贝,这个函数是针对内存块进行拷贝的

函数原型

cpp 复制代码
void* memcpy(void* destination,const void* source, size_t num);

从source位置开始,向后num个数据拷贝到destination中,它与字符串的strcopy类似,但是遇到'\0'不会停下来,同时,两者的内存不能重叠

我们先来写代码使用一下爱这个函数吧

cpp 复制代码
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };

	my_memcpy(arr2, arr1, 20);	//字节的长度
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		printf("%d ", arr2[i]);
	}

	return 0;
}

在这个代码中,我们将arr1的内容拷贝到了arr2中,拷贝了20个字节,也就是5个int类型的数字,一定要注意是字节的拷贝,这是运行结果

现在,我们来模拟实现这个函数吧

cpp 复制代码
void* my_memcpy(void* dest, void* src, size_t num)
{
	int i = 0;
	void* ret = dest;
	assert(dest && src);
	/*for (i = 0; i < num; i++)
	{
		*((char*)dest + i) = *((char*)src + i);
	}*/

	while (num--)
	{
		*(char*)dest = *(char*)src;
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}

那如果我们想实现在一个数组内进行操作,比如我想操作arr1数组,把第二个数字开始更改,进行拷贝,如果我们写出如下的代码,可能运行结果与我们考虑的就不同了

cpp 复制代码
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };

	my_memcpy((arr1+2), arr1, 20);	//字节的长度
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}

	return 0;
}

我们想要得到的是 1,2,1,2,3,4,5,8,9,10,但实际结果是:

实际上,这是因为memcpy是不能有内存重叠的,这样我们先更改了,然后再访问,因此出现了很多个1,2

当然,VS有保护机制,我们现在也可以使用memcpy来实现了,但理论上 是不行的

2.memmove

memmove和memcopy的差别是memmove函数处理源内存块和目标内存块是可以重叠的,最后返回目标空间的起始地址

函数原型

cpp 复制代码
void* memmeove(void* dest, const void* src, size_t num)

现在,我们可以运用这个函数来实现了

cpp 复制代码
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove((arr + 2), arr, 5*sizeof(int));
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

现在,我们来看看结果是否和我们想要的一样?

那么,我们是否可以尝试进行模拟这个函数呢?

第一种方法,我们在函数中再创建一个数组,将内容拷贝过去,然后再进行

那我们是否可以不创建新数组,来实现这个函数呢?

事实上,我们可以根据dest和scr的位置来判断

当dest在src之前时,我们从前向后进行拷贝,当dest在src后面时,我们从后向前进行拷贝,因此,我们可以写出以下的代码

cpp 复制代码
void* my_memmeove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src)
	{
		while (num--)
		{
			*(char*)dest = *(char*)src;
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else
	{
		while (num--)
		{
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	return ret;
}

3.memset

是用来完成内存设置的

函数原型:

cpp 复制代码
void * memset(void* ptr,int vulue,size_t num);

ptr代表要填充的内存块的位置,vulue是设置的值,num是填充几个字节的位置

现在我们来使用这个函数吧!

cpp 复制代码
int main()
{
	char arr[] = "hello world";
	memset(arr, 'x', 5);
	printf("%s ", arr);

	return 0;
}

这里,我们将前五个字符变成了x,结果如下:

当然,也不仅限于字符串函数,整形函数也可以,但是我们需要注意,这里是把所有的字节转换,而int类型占据4个字节,应该注意如何来运用

4.memcmp

完成内存块的比较

函数原型

cpp 复制代码
int memcmp(const void* ptr1, const void* ptr2, size_t num);

从ptr1与ptr2开始num个字节进行比较,返回值是数字,前者大返回大于0的,后者大返回小于0的,相等返回0

我们来使用这个函数吧

cpp 复制代码
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7 };
	int arr2[] = { 1,2,3,4,8,8,8 };
	int ret = memcmp(arr1, arr2, 16);
	printf("%d ", ret);

	return 0;
}

结果是这样

感谢您的观看

相关推荐
wuminyu23 分钟前
HotSpot的轻量锁与膨胀后的ObjectMonitor状态重建原理
java·linux·c语言·jvm·c++
CoderYanger31 分钟前
A.每日一题:835. 图像重叠
java·开发语言·程序人生·leetcode·面试·职场和发展·学习方法
码不停蹄Zzz1 小时前
指针用法篇——malloc和free指针详解
c语言
伞伞悦读1 小时前
【第37期】Python JSON 与配置详解:序列化、反序列化、嵌套结构和配置文件
开发语言·python·json
CCCCCCCCharlie1 小时前
Linux进程控制四大核心操作
linux·开发语言
彧azz2 小时前
操作系统时间管理与系统核心板块学习总结
c语言·笔记·学习·系统架构
白色的北极熊2 小时前
c语言 牛客网 BC15
c语言
Brilliantwxx2 小时前
【STM32】 SPI Flash 驱动开发实战:阻塞模式驱动 W25Q64(含工程代码)
开发语言·stm32·单片机·嵌入式硬件
wuyk5552 小时前
【Socket 进阶之路】第 9 章 Linux 网络服务量产稳定性优化|心跳保活、TIME_WAIT、SO_LINGER、内存池、断线重连、完整异常防护框架
linux·服务器·开发语言·网络·物联网
邪修king2 小时前
Re:Linux 系统篇(三十四):进程间通信开篇Chapter1 —— 匿名管道 pipe 深度拆解与代码实战
android·linux·运维·开发语言