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;
}

结果是这样

感谢您的观看

相关推荐
梦想平凡7 小时前
情怀源代码工程实践(加长版 1/3):确定性内核、事件回放与最小可运行骨架
开发语言·javascript·ecmascript
笑我归无处7 小时前
强引用、软引用、弱引用、虚引用详解
java·开发语言·jvm
02苏_7 小时前
秋招Java面
java·开发语言
ytttr8737 小时前
64QAM信号的数字预失真处理(MATLAB实现)
开发语言·matlab
Nebula_g7 小时前
C语言应用实例:硕鼠游戏,田忌赛马,搬桌子,活动选择(贪心算法)
c语言·开发语言·学习·算法·游戏·贪心算法·初学者
爱吃甜品的糯米团子7 小时前
详解 JavaScript 内置对象与包装类型:方法、案例与实战
java·开发语言·javascript
QT 小鲜肉7 小时前
【Git、GitHub、Gitee】按功能分类汇总Git常用命令详解(超详细)
c语言·网络·c++·git·qt·gitee·github
郝学胜-神的一滴7 小时前
Linux下,获取子进程退出值和异常终止信号
linux·服务器·开发语言·c++·程序人生
AI科技星8 小时前
张祥前统一场论动量公式P=m(C-V)误解解答
开发语言·数据结构·人工智能·经验分享·python·线性代数·算法