C语言部分内存函数详解

前言

在我的C语言-部分字符串函数详解 1-4C语言-部分字符串函数详解 5-10中,函数的操作对象为字符串,如果想处理其他类型的数据,则需用到内存函数
本文将介绍<string.h>头文件下的部分内存函数:

  • 1.memcpy
  • 2.memmove
  • 3.memset
  • 4.memcmp

1.memcpy


函数原型:void * memcpy ( void * destination, const void * source, size_t num );
简介:Copy block of memory——拷贝一块内存

1.1基本用法

会从source向后拷贝num字节的内容至destination

int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 0 };
memcpy(arr2, arr1, 5*sizeof(int));
for (int i = 0; i < 5; i++)printf("%d ", arr2[i]);

运行结果:
在这里插入图片描述

1.2注意事项

目标空间与原空间不能重叠

如果重叠,拷贝的结果未定义,需使用memmove处理重叠的情况。
在VS2022上,重叠对拷贝结果无影响:

int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
memcpy(arr1+3, arr1, 5*sizeof(int));
for (int i = 0; i < 10; i++)printf("%d ", arr1[i]);

运行结果:
在这里插入图片描述

但C语言标准中拷贝的结果未定义,因此仍不建议使用memcpy拷贝有重叠的情况。

目标空间原数据会被覆盖

int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[10] = { 9,9,9,9,9 };
memcpy(arr2, arr1, 5*sizeof(int));
for (int i = 0; i < 5; i++)printf("%d ", arr2[i]);

运行结果:
在这里插入图片描述

目标空间要够大

int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
int arr2[5];
memcpy(arr2, arr1, 10*sizeof(int));
for (int i = 0; i < 5; i++)printf("%d ", arr2[i]);

运行结果:
在这里插入图片描述

VS2022给出了相应的警告:在这里插入图片描述

拷贝字节数需小于原空间大小

int arr1[5] = { 1,2,3,4,5 };
int arr2[10];
memcpy(arr2, arr1, 10 * sizeof(int));
for (int i = 0; i < 10; i++)printf("%d ", arr2[i]);

运行结果:
在这里插入图片描述

VS2022给出了相应的警告:在这里插入图片描述

1.3模拟实现

void* my_memcpy(void* dst, const void* src, size_t num)
{
	assert(dst && src);
	void* ret = dst;
	while (num--)*((char*)dst)++ = *((char*)src)++;
	return ret;
}

为了处理多种类型的数据,我们传入void*的指针,在强转成char,这样在拷贝时可以按字节依次拷贝。

2.memmove


函数原型:void * memmove ( void * destination, const void * source, size_t num );
简介:Move block of memory——拷贝一块内存

2.1基本用法

memmovememcpy的用法基本一致,且memmove可处理有重叠的空间。

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

运行结果:
在这里插入图片描述

2.2注意事项

memcpy的基本一致,且memmove可处理有重叠的空间。

2.3模拟实现

memcpy的模拟实现中,我只是单方向的进行拷贝,完成了C语言对memcpy的基本要求。
而在memmove的模拟实现中,如果单方向进行拷贝,会在空间重叠时出现拷贝了新数据的现象,因此需判断拷贝方向。

void* my_memmove(void* dst, const void* src, size_t num)
{
	assert(dst && src);
	void *ret = dst;
	if (dst < src)
	{
		while (num--)*((char*)dst)++ = *((char*)src)++;
		return ret;
	}
	else
	{
		while (num--)*(((char*)dst) + num) = *(((char*)src) + num);
		return ret;
	}
}

3.memset


函数原型:void * memset ( void * ptr, int value, size_t num );
简介:Fill block of memory——填充内存块

3.1基本用法

按字节设置内存,可用于初始化

typedef struct Peo
{
	char name[20];
	int age;
	char tele[12];
}Peo;
typedef struct Contact
{
	struct Peo peo[100];
	int num;
}Contact;
int main()
{
	Contact con;
	Contact* p = &con;
	memset(p->peo, 0, sizeof(p->peo));
	return 0;
}

这段代码是我写的通讯录里的。
定义了两个结构体类型 PeoContactPeo 结构体包含姓名、年龄和电话号码。而 Contact 结构体则包含一个 Peo 类型的数组,以及一个整型变量 num,用于记录实际存储了多少个联系人。

main 函数中,首先创建了一个 Contact 类型的变量 con,接着定义了一个指向 Contact 类型的指针 p 并将其指向 con。然后使用 memset 函数将 p->peo 数组中的所有元素初始化为0

初始化效果:

对于 char 类型的数组,这会使它们只包含空字符。
对于 int 类型的成员,这会将它们初始化为0
数组大小:sizeof(p->peo) 返回的是整个 peo 数组的大小,即100个 Peo 结构体的总大小。

4.memcmp


函数原型:int memcmp ( const void * ptr1, const void * ptr2, size_t num );
简介:Compare two blocks of memory——比较两个内存块

4.1基本用法

char ch1[] = "aaaa";
char ch2[] = "aaab";
int n= memcmp(ch1, ch2, 4);
if (n > 0)printf(">");
else if (n < 0)printf("<");
else printf("=");

运行结果:
在这里插入图片描述

4.2注意事项

按字节比较

不管什么类型的数据,memcmp都是按字节比较,这使得有时候不能得到预期结果:

int arr1[10] = { 1 };
int arr2[10] = { 256 };
int n = memcmp(arr1, arr2, 4);
if (n > 0)printf(">");
else if (n < 0)printf("<");
else printf("=");

运行结果:
在这里插入图片描述
1肯定比256小,但我们比的规则是逐字节
在小端存储的机器上:
1在内存:
在这里插入图片描述
256在内存:
在这里插入图片描述
由于是逐字节比较,所以结果是1>256


希望本篇文章对你有所帮助!
本人仅仅是个C语言初学者,如有任何意见,欢迎各位提出!


相关文章:
C语言指针详解-上
C语言指针详解-下

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值