字符串操作函数之内存操作函数

本文讲解了C语言中的memcpy、memmove和memcmp内存操作函数,包括它们的用法、注意事项,以及如何模拟实现。通过实例演示了如何在不同场景下正确使用这些函数,以及它们在处理重叠内存和字符串操作中的作用。
摘要由CSDN通过智能技术生成

学习目标:

掌握使用规律,及部分模拟实现

对比前一篇文章的那些个字符串操作函数,提出内存操作函数,是为了挣脱前述内容仅能操作字符串的束缚。


学习内容:

1:memcpy

①:标准格式:void * memcpy ( void * destination, const void * source, size_t num );

②:含义:从source起拷,拷num个字节的内容,从destination起放。返回destination。

③:注意事项:

     (a):该函数是针对底层数据的二进制副本,该函数不会去检查源字符串中的任何字符串结束标志,你给这个函数一个源地址,它总会从这开始精确的拷贝num个字节内容放到destination所指向的空间,所以说,目标空间和源空间都至少有num个字节内容才安全。

      (b):目标空间和源空间不要有重叠的部分,若有重叠的部分建议使用更加安全的memmove函数,具体往下看。

④:使用案例:

#include <stdio.h>
#include <string.h>
struct stu
{
	char name[50];
	int age;
}s1;
int main()
{
	char myname[] = "i am a good student";
	memcpy(s1.name, myname, strlen(myname) + 1);
	printf("%s\n", s1.name);
	return 0;
}

⑤:模拟实现

#include <stdio.h>
void* my_memcpy(void* destination, const void* source, size_t num)
{
	char* ret = (char*)destination;
	int i = 0;
	for (i = 0; i < num; i++)
	{
		*(char*)destination = *(char*)source;
		destination = (char*)destination + 1;
		source = (char*)source + 1;
	}
	return ret;
}
struct stu
{
	char name[50];
	int age;
}s1;
int main()
{
	char myname[] = "i am a good student";
	char*ret=my_memcpy(s1.name, myname, strlen(myname) + 1);
	printf("%s\n", ret);
	return 0;
}

⑥若非要在源空间和目标空间有重叠时使用memcpy会怎么样?

 离谱的事情发生了!结果居然是在预料当中!,这其实是VS2019足够强大,那如果用我们自己模拟实现的那个代码去操作这个图片内容:

可以发现,非理想效果。代码摆在这,其实可以预想得到这个结果。如下:(其实memcpy就是周这么实现的,只不过它有优化的空间,可以防止源目有重叠情况的发生,且VS2019做到了,我们没做到

 


2:memmove 

①:格式:void * memmove ( void * destination, const void * source, size_t num );

②:含义:就是比memcpy多了一个适用范围,即:它可以允许我们在源空间和目标空间出现重叠时使用,它这样就像是使用了一个中间缓冲区一样的东西。同样的,该函数是不会检查源空间中的任何终止空字符的,所以说,使用时它总是精准的赋值num个字节的内容,你只不过是给它一个起点而已。为了避免溢出,目标空间和源空间内容不得少于num个字节的内容哦。

③:使用案例:

④:memmove的模拟实现 

先理解一下思想:在这先给一个arr[]={1,2,3,4,5,6,7,8,9,10};

通过上述的理解,是不是该明白: 有重叠空间的memcpy或者说memmove去模拟实现的话,可不可以总结成这样:对source:把前面的数据拿到后面,那对source来说,就从后面开始拷贝,逐个往前一个个拷贝,然后放到destination,反之则反。

#include <stdio.h>
void* my_memmove(void* destination, const void* source, size_t num)
{
	void* ret = destination;
	if (destination > source)//source中的数据往后拿,拷贝顺序是从后往前
	{
		while (num--)
		{
			*((char*)destination+num) = *((char*)source+num);
		}
	}
	else//source中的数据往前拿,拷贝顺序是从前往后
	{
		while (num--)
		{
			*(char*)destination = *(char*)source;
			destination = (char*)destination + 1;
			source = (char*)source + 1;
		}
	}
	return  ret;
}
int main()
{
	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	my_memmove(arr + 2, arr, 16);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

 


3:memcmp

①:格式:int memcmp ( const void * ptr1, const void * ptr2, size_t num );

②:含义:从ptr1和ptr2开始,逐一比对字节数据是否一致,不一致返回非零,一致则返回0

③:使用案例:

#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = {1,2,3,4,5};//小端:01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00
	int arr2[] = {1,2,3,5,4};//小端:01 00 00 00 02 00 00 00 03 00 00 00 05 00 00 00 04 00 00 00
	int ret=memcmp(arr1, arr2, 13);
	printf("%d\n", ret);
	return 0;
}

4:memset

①:格式:void * memset ( void * ptr, int value, size_t num );

②:含义:ptr指向的内存块的前num个字节设置为指定(解释为unsigned char)。

③:使用案例:

 


5:补充:strerror

①:格式:char * strerror ( int errnum );

②:含义:errnum为错误码,给strerror一个错误码,它就给你这个错误码所对应的错误信息(字符串)。

③:使用案例:


6:perror 

①格式:void perror ( const char * str );

②:含义:先以%s打印str,然后跟一个冒号一个空格,再接一个strerror的功能!并且,str是否为NULL都不影响错误报告的打印并\n

③:使用案例:

 上述仅供参考


学习时间:

2021.10


学习产出:


1、 技术笔记 2 遍
2、CSDN 技术博客 1 篇
3、 gitee

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值