C语言第20讲

C语言内存函数

memcpy的使用和模拟实现

作用:针对内存块进行拷贝

声明:

void * memcpy ( void * destination, const void * source, size_t num );

destination 待粘贴内存块地址

source 复制内存块地址

num 决定更改多大内存,单位字节

从 source 的位置开始向后复制 num 个字节的数据到 destination 指向的内存空间

(遇到 \0 不会停止)

头文件:string.h

memcpy 的使用:

memcpy 的模拟实现:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <string.h>
#include <assert.h>

void* my_memcpy(void* p1, const void* p2, size_t num)
{
	assert(p1 && p2);
	void* s1 = p1;							// 尽量不对传参值进行修改
	const void* s2 = p2;
	while (num--)
	{
		*(char*)s1 = *(char*)s2;
		// 第一类指针偏移(推荐)			// 第二类指针偏移
		s1 = (char*)s1 + 1;					// ((char*)s1)+1;
		s2 = (char*)s2 + 1;					// ((char*)s2)+1;
	}
	return p1;
}

int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[] = { 8,8,8,8,8 };

	my_memcpy(arr1 + 2, arr2, 20);			
	for (int i = 0; i < 10; i++)
		printf("%d ", arr1[i]);
	return 0;
}

当 source 和destination 内存有任何的重叠时,复制的结果不保证

例如:

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

当你尝试模拟实现的 emecpy 函数整流程走一变时

会发现样本空间指向3时,已经被修改为了1

所以导致最后打印结果为:

1 2 1 2 1 2 1 8 9 10

不是理想的

1 2 1 2 3 4 5 8 9 10

当想打印具有重叠内存的空间时用 ememove 函数

memmove 的使用和模拟实现

声明:和memcpy一样

void * memcpy ( void * destination, const void * source, size_t num );

destination 待粘贴内存块地址

source 复制内存块地址

num 决定更改多大内存,单位字节

使用方式也一样,区别在于 memmove 多了个处理重叠内存的功能

memmove 的模拟实现:

回到上一个问题如何解决?

1.在替换前复制整个模版内存一次

这个方式可以解决,但是有个更为巧妙的方式

当你的指针由后向前开始替换时会发现,在打印时不会将样本空间覆盖掉

但是情况反转呢?

会发现由后向前替换会出现问题

但由前向后,问题就会解决

我现在发现如果空间出现重叠现象,只会有

上图两种情况,和一种完全重叠情况

但空间完全重叠和 空间不重叠 两种替换方式都能解决

所以我们只需分两类情况

1.样本空间在被修改空间后方

重叠区域在样本空间前方

举个例子:现在有 2 瓶冰红茶,一瓶快过期了,一瓶时间还长着

一般是先将快过期的喝掉,再喝时间还长的

这个样本空间也一样,先用空间重叠的后用未重叠的

所以为右前向后替换

2.样本空间在被修改空间前

重叠空间在样本空间后放

所以由后向前替换

现在替换方式对于什么情况确定了,还需要确定一个什么条件判断一个什么情况

由于指针一直处于空间的最左侧,所以我们可以利用指针的大小确定情况

而且,数组在空间中由低向高存放

所以:

1.样本空间在被修改空间后方(由前向后)

样本空间指针打印被修改空间指针

p2 > p1

2.样本空间在被修改空间前方(由后向前)

样本空间指针小于被修改空间

p2 < p1

代码如下:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 
#include <stdio.h>
#include <assert.h>

void* my_memmove(void* p1, const void* p2, size_t num)
{
	assert(p1 && p2);
	void* s1 = p1;
	const void* s2 = p2;
	if (p2 > p1)
	{
		while (num--)
		{
			*(char*)s1 = *(char*)s2;
			s1 = (char*)s1 + 1;
			s2 = (char*)s2 + 1;
		}
	}
	else
	{
		s1 = (char*)s1 + num - 1;     // 解决有后向前,指针最开始在后方
		s2 = (char*)s2 + num - 1;
		while (num--)
		{
			*(char*)s1 = *(char*)s2;
			s1 = (char*)s1 - 1;
			s2 = (char*)s2 - 1;
		}
	}
	return p1;
}

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

	my_memmove(arr1, arr1 + 2, 20);
	for (int i = 0; i < 10; i++)
		printf("%d ", arr1[i]);

	printf("\n");

	int arr2[] = { 1,2,3,4,5,6,7,8,9,10 };

	my_memmove(arr2+2, arr2, 20);
	for (int i = 0; i < 10; i++)
		printf("%d ", arr2[i]);
	return 0;
}

memset 的使用

声明:

void * memset ( void * ptr, int value, size_t num );

ptr 修改空间的地址

int 需要修改成的内容

num 需要修改的空间,大小为字节

memset 的使用:

memcmp 的使用

声明:

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

比较从ptr1和ptr2指针指向的位置开始,向后的num个字节

和 strcmp 类似只不过这个比较的是内存中的内容(区别不大)

memcmp 的使用:

区别在于memcmp可以比较任意类型


相关推荐
星火开发设计1 分钟前
C++ deque 全面解析与实战指南
java·开发语言·数据结构·c++·学习·知识
ID_180079054738 分钟前
除了Python,还有哪些语言可以解析淘宝商品详情API返回的JSON数据?
开发语言·python·json
草莓熊Lotso11 分钟前
Qt 信号与槽深度解析:从基础用法到高级实战(含 Lambda 表达式)
java·运维·开发语言·c++·人工智能·qt·数据挖掘
superman超哥1 小时前
Rust 异步错误处理最佳实践
开发语言·rust·编程语言·rust异步错误处理·rust最佳实践
脏脏a1 小时前
C++ STL list 模拟实现:从底层链表到容器封装
开发语言·c++·stl·双链表
故事不长丨8 小时前
C#正则表达式完全攻略:从基础到实战的全场景应用指南
开发语言·正则表达式·c#·regex
哈库纳玛塔塔9 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
你怎么知道我是队长9 小时前
C语言---typedef
c语言·c++·算法
phltxy10 小时前
从零入门JavaScript:基础语法全解析
开发语言·javascript
带土110 小时前
5. enum(枚举)关键字在C/C++中的作用
c语言·c++