【C语言】_内存拷贝函数memcpy与memmove

目录

[1. memcpy](#1. memcpy)

[1.1 函数声明及功能](#1.1 函数声明及功能)

[1.2 使用示例](#1.2 使用示例)

[1.3 模拟实现](#1.3 模拟实现)

[2. memmove](#2. memmove)

[2.1 函数声明与功能](#2.1 函数声明与功能)

[2.2 使用示例](#2.2 使用示例)

[2.3 模拟实现](#2.3 模拟实现)


1. memcpy

在专栏前文已介绍字符串拷贝函数strcpy,但其仅能实现字符串的拷贝。若需对其他类型如整型、浮点型、结构体等变量进行拷贝,则无法再使用strcpy实现。

memcpy函数针对内存块实现拷贝;

1.1 函数声明及功能

cpp 复制代码
void * memcpy ( void * destination, const void * source, size_t num );

memcpy函数功能:

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

返回值为拷贝的目标空间的起始地址;

注:1、memcpy在遇到\0时并不会停止;

2、如果source和destination有任何重叠,memcpu的行为是未定义的,可能导致数据损坏

3、memcpy虽然为内存拷贝函数,但使用时所需包含的头文件为string.h

1.2 使用示例

cpp 复制代码
#include<stdio.h>
#include<string.h>
int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1,5*4);
	for (int i =0; i < 20; i++) {
		printf("%d ", arr2[i]);
	}
	return 0;
}

运行结果如下:

1.3 模拟实现

cpp 复制代码
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* src, size_t num) {
	assert(dest && src);
	int i = 0;
	void* ret = dest;
	// num单位为字节(而非元素)
	while (num--) {
		// 逐字节拷贝
		*((char*)dest) = *((char*)src);
		src = (char*)src + 1;
		dest = (char*)dest + 1;
	}
	// 返回拷贝的目标空间的起始地址
	return ret;
}
int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1,7*4);
	for (int i =0; i < 20; i++) {
		printf("%d ", arr2[i]);
	}
	return 0;
}

注:对于src = (char*)src + 1,不可写为src++,src为void*类型,不可直接进行加减运算;

但可写为((char*)src)++,表示强转为char*类型后再自增;

2. memmove

对于memcpy,它只负责不重叠空间的内存拷贝工作,在注2中已经提到;

若需实现拷贝的源和目标内存区域有重合部分的内容拷贝,则需使用memmove函数

2.1 函数声明与功能

cpp 复制代码
void * memmove ( void * destination, const void * source, size_t num );

注:对于调用者,相较于memcpy,memmove并未增加额外的参数。其可以实现重叠内存区域的拷贝的逻辑,在模拟实现部分进行说明;

2.2 使用示例

cpp 复制代码
#include<stdio.h>
#include<string.h>
int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	// 将1、2、3、4、5拷贝至3、4、5、6、7位置处
	memmove(arr1 + 2, arr1, 5 *sizeof(int));
	for (int i = 0; i < 10; i++) {
		printf("%d ", arr1[i]);
	}
	return 0;
}

运行结果如下:

2.3 模拟实现

memmove可以处理源内存区域和目标区域有重叠的情况,模式实现具体实现逻辑有两种:

(1)额外再开辟一个数组作为临时缓冲区,先将源内存区域的数据复制到一个临时缓冲区,再从临时缓冲区复制到目标内存区域,确保数据不会被覆盖;(两次拷贝实现,此处不再)

(2)分情况从前向后或从后向前依次将源内存空间数据拷贝至目标内存空间:

情况1:

情况2:

情况3:

现将情况2与3合并,故对src与dest分段如下:

当dest落在src之前时,从前向后依次拷贝;

当dest落在src之后时,从后向前依次拷贝;

cpp 复制代码
#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memmove(void* dest, const void* src, size_t num) {
	assert(src && dest);
	void* ret = dest;
	if (dest < src) {
		// 从前向后依次拷贝
		while (num--) {
			*((char*)dest) = *((char*)src);
			dest = (char*)dest + 1;
			src = (char*)src + 1;
		}
	}
	else {
		// 从后向前依次拷贝
		while (num--) {
			*((char*)dest + num) = *((char*)src + num);
		}
	}
	// 返回目标空间的起始地址
	return ret;
}
void PrintInt(int* arr, int sz) {
	for (int i = 0; i < sz; i++) {
		printf("%d ", *(arr + i));
	}
	printf("\n");
}
int main() {
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int sz = sizeof(arr1) / sizeof(arr1[0]);
	// 将1、2、3、4、5拷贝至3、4、5、6、7位置处
	my_memmove(arr1 + 2, arr1, 5 * sizeof(int));
	PrintInt(arr1, sz);
	int arr2[] = { 1,2,3,4,5,6,7,8,9,10 };
	// 将3、4、5、6、7拷贝至1、2、3、4、5位置处
	my_memmove(arr2, arr2 + 2, 5 * sizeof(int));
	PrintInt(arr2, sz);
	return 0;
}

测试用例运行结果如下:

相关推荐
小庞在加油29 分钟前
Apollo源码架构解析---附C++代码设计示例
开发语言·c++·架构·自动驾驶·apollo
森焱森1 小时前
60 美元玩转 Li-Fi —— 开源 OpenVLC 平台入门(附 BeagleBone Black 驱动简单解析)
c语言·单片机·算法·架构·开源
专注VB编程开发20年1 小时前
各版本操作系统对.NET支持情况(250707更新)
开发语言·前端·ide·vscode·.net
我喜欢就喜欢1 小时前
RapidFuzz-CPP:高效字符串相似度计算的C++利器
开发语言·c++
千帐灯无此声1 小时前
Linux 测开:日志分析 + 定位 Bug
linux·c语言·c++·bug
莫彩1 小时前
【Modern C++ Part7】_创建对象时使用()和{}的区别
开发语言·c++
星光54221 小时前
飞算JavaAI:给Java开发装上“智能引擎”的超级助手
java·开发语言
June bug2 小时前
【Python基础】变量、运算与内存管理全解析
开发语言·python·职场和发展·测试
醇醛酸醚酮酯2 小时前
Qt项目锻炼——TODO(五)
开发语言·qt
蹦蹦跳跳真可爱5892 小时前
Python----OpenCV(几何变换--图像平移、图像旋转、放射变换、图像缩放、透视变换)
开发语言·人工智能·python·opencv·计算机视觉