关注

深入理解C语言内存操作函数

内存函数是直接操作计算机中内存的函数,它不关心内存中存放的是什么数据,它只按照一块块内存字节去拷贝、移动、设置、比较。使用内存函数需要包含头文件<string.h>

memcpy函数的使用和模拟实现

memcpy(memory copy)函数是用来对内存进行拷贝的,它包含三个参数void* dest,const void* src和size_t count,如strncpy函数一样,这三个参数分别是,指向目标的指针,指向源头的指针和要拷贝的字节数。函数返回值类型为void*型,返回的是目标的起始地址。使用的时候也是要保证目标空间足够大且可修改。
注意:memcpy函数只负责不重叠的两块内存数据的拷贝。
在这里插入图片描述

memcpy函数的使用

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	//想把arr1中的前五个元素拷贝到arr2中,也就是20个字节数 
	memcpy(arr2, arr1, 20);
	return 0;
}

在这里插入图片描述

memcpy函数的模拟实现

要实现拷贝内存数据的任意字节数这一功能,我们设计三个参数void* dest,const void* src,size_t num,dest是指向目标的指针,src是指向源头的指针,num是内存中要进行拷贝的字节数,我们不清楚会传过来什么类型的指针,就把dest和src类型都设为void* ,我们不会修改src指向的内容,用const修饰更安全点。返回值是目标的起始地址,我们就创建一个指针变量ret用于存目标的起始地址。开头再加上assert断言,确保传过来的指针的有效性

函数主要逻辑:我们知道void* 指针不能直接解引用,我们要想每个字节地进行拷贝,可以把void* 强制转换为char* 再解引用进行拷贝,就可以实现这一功能了。
程序如下:

#include<stdio.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num)
{
	//确保指针有效性
	assert(dest && src);
	//存目标起始地址
	void* ret = dest;
	//每个字节进行拷贝
	while (num--)
	{
		*(char*)dest = *(char*)src;
		//找到下一个字节的地址
		dest = (char*)dest + 1;
		src = (char*)src + 1;
	}
	return ret;
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	my_memcpy(arr2, arr1, 20);
	return 0;
}

在这里插入图片描述
调试发现程序功能正常。

memmove函数的使用和模拟实现

memmove(memory move)函数是用来处理两个重叠的内存数据的拷贝(不重叠也能处理)。参数和返回值与memcpy一模一样,函数使用方法和实现逻辑也是。
在这里插入图片描述

memmove函数的使用

#include<stdio.h>
#include<string.h>
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//想把1~5拷贝到3~7上
	memmove(arr + 2, arr, 20);
	//让数组变成1,2,1,2,3,4,5,8,9,10
	return 0;
}

在这里插入图片描述

memmove函数的模拟实现

参数和返回值与上面设计的memcpy一模一样,问题在于重叠的两个内存数据的拷贝该如何处理?
重叠的两块内存数据有两种情况:
情况1:
在这里插入图片描述

当目标在源头后面的时候,如果我们从前往后拷贝,就会覆盖源头中原来存放的值。
在这里插入图片描述
所以应该从后往前拷贝。
情况2:
在这里插入图片描述
这种情况下从前往后拷贝就不会覆盖了。

总结下来就是,目标在源头前面就从前往后拷贝,目标在源头后面就从后往前拷贝。
判断目标在源头的前面还是后面可以直接比较dest和src的地址,因为数组在内存中的存放是连续的,越往后地址越大。

函数主要逻辑:先判断目标在源头前面还是后面,在前则从前往后打印,和memcpy拷贝逻辑一样,在后则从后往前打印,从最末尾开始往前拷贝。
程序如下:

#include<stdio.h>
#include<assert.h>
void* my_memmove(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;
}
int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memmove(arr + 2, arr, 20);
	return 0;
}

在这里插入图片描述
调试发现程序功能正常。

memset函数的使用

memset(memory set)是用来内存设置的函数,包含三个参数void* dest,int ch,size_t num,其中dest是目标,ch是填充进去的内容,count是填充的字节数。返回的是目标的起始地址。memset会对每个字节都进行填充。
在这里插入图片描述

#include<stdio.h>
#include<string.h>
int main()
{
	char arr[] = "abcdedgfdg";
	//想把c到f的内容填充成x
	memset(arr + 2, 'x', 6);
	return 0;
}

在这里插入图片描述
需要注意的是,memset是每个字节都进行内容填充,如果想把整型数组元素都填充成1是不可能的,其他大于1字节的类型也是一样。

memcmp函数的使用

memcmp(memory compare)函数是进行内容比较的函数,按照每个字节去进行比较,包含三个参数:const void* lhs,const void* rhs,size_t count,前两个指针是分别指向要比较的内容,第三个是进行比较的字节数。
它的返回值逻辑和strcmp一样,
lhs>rhs则返回大于0的数
lhs==rhs则返回等于0的数
lhs<rhs则返回小于0的数
在这里插入图片描述

#include<stdio.h>
#include<string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,3,4,0 };
	int r = memcmp(arr1, arr2, 16);
	printf("%d\n", r);
	return 0;
}

在这里插入图片描述
如果比较的字节数变成17,则结果是:
在这里插入图片描述

转载自CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/l1147195799/article/details/160956658

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--