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


相关推荐
跨境数据猎手39 分钟前
反向海淘实战|独立站搭建+国内电商API对接
开发语言·爬虫·架构
没钥匙的锁11 小时前
05-Java面向对象构造器与封装
java·开发语言
仙人球部落1 小时前
-python-LangGraph框架(3-31-LangGraph 「合并式状态管理」的原理与实践)
开发语言·javascript·python
2401_894915531 小时前
Geo搜索优化排名源码部署搭建全流程详解
android·开发语言·flask·php·精选
chouchuang2 小时前
day-025-面向对象-上
开发语言·python
某不知名網友2 小时前
C/C++动态内存管理,智能指针及RAlI思想。
java·c语言·c++
sunfdf2 小时前
Next.js 新手从零部署到首跑实战指南
开发语言·javascript·ecmascript
一杯奶茶¥3 小时前
c语言程序设计大学期末考试考研知识点重点笔记题库复习资料C语言重点考点题库资料合集
c语言·笔记·考研·c语言程序设计·c语言笔记
hold?fish:palm3 小时前
从源码到可执行文件:C++程序的编译过程
开发语言·c++
随性而行3603 小时前
微信API接口与AI自动化:开发者的实现思路
运维·服务器·开发语言·人工智能·微信·自动化