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可以比较任意类型


相关推荐
kcoo2 小时前
Jupyter Lab 汉化
linux·开发语言·python
Terio_my3 小时前
Java 后端面试技术文档(参考)
java·开发语言·面试
biomooc3 小时前
D3.js 与数据可视化
开发语言·javascript·信息可视化
我要成为c嘎嘎大王3 小时前
【C++】内存管理
开发语言·c++
Dream achiever4 小时前
8.WPFTextBox控件的鼠标和键盘事件
开发语言·c#·wpf
苏纪云4 小时前
算法<java>——排序(冒泡、插入、选择、归并、快速、计数、堆、桶、基数)
java·开发语言·算法
杨福瑞4 小时前
C语言⽂件操作讲解(1)
c语言·开发语言
艾莉丝努力练剑4 小时前
【C++STL :string类 (二) 】从接口应用到内存模型的全面探索
linux·开发语言·c++·经验分享
YQ_ZJH4 小时前
Java List列表创建方法大总结
java·开发语言·数据结构·算法·list