专栏:C语言


这次我会根据标准C库函数参考,对 memcpy、memmove、memset、memcmp 四个内存操作函数进行标准定义、参数说明、举例以及各自函数的模拟实现。

前言

在C语言编程中,字符串函数能处理以 \0 结尾的字符数据,适用场景有限。而内存操作函数直接以字节为单位对任意类型数据进行拷贝、移动、赋值与比较,不依赖数据类型、不受结束符限制,是编写通用、高效、底层代码的核心工具。本篇将学习memcpy、memmove、memset、memcmp四大内存函数,从用法、原理到手写模拟实现全覆盖,帮助大家真正掌握内存层面的数据操作逻辑,提升代码的健壮性与编程能力。

一.memcpy -----> 内存块拷贝

1.1函数原型(包含功能,参数,返回值)

函数原型:

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

功能:

  1. source 指向的内存,向后复制 num 个字节 destination 指向的内存
  2. 不关心数据类型,只做二进制级别的逐字节拷贝
  3. 如果两块内存存在重叠时,复制结果为未定义行为
  4. 头文件:<string.h>

参数:

  1. destination:目标内存起始地址
  2. source:源内存起始地址
  3. num:要复制的字节数

返回值:

返回目标内存 destination 的起始地址。

1.2举例

#include <stdio.h>
#include <string.h>

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

🧐分析:先定义两个整型数组,arr1 为源数据,arr2 为目标空间;然后调用 memcpy拷贝20字节(相当于5个int);最后循环打印 arr2 内容。

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

1.3memcpy的模拟实现

#include <assert.h>

void * my_memcpy(void * dst, const void * src, size_t count)
{
	void * ret = dst;
	assert(dst != NULL);
	assert(src != NULL);
	while (count--)
	{
		*(char *)dst = *(char *)src;
		dst = (char *)dst + 1;
		src = (char *)src + 1;
	}
	
	return ret;
}

🧐分析:用 assert 断言保证指针非空;再强转为 char* 实现逐字节拷贝,保证通用性;接着循环 count 次,完成指定字节数拷贝;最后返回复制后目标空间地址。

二.memmove -----> 内存块拷贝(⬅️可处理重叠)

2.1函数原型(包含功能,参数,返回值)

函数原型:

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

功能:

  1. 功能与 memcpy 一致,但可以安全处理内存重叠
  2. 无论源、目标内存是否重叠,都能正确复制。
  3. 头文件:<string.h>

参数:

  1. destination:目标内存起始地址
  2. source:源内存起始地址
  3. num:要复制的字节数

返回值:

返回目标内存 destination 的起始地址。

2.2举例

#include <stdio.h>
#include <string.h>

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

🧐分析:先在同一个数组内进行拷贝,存在内存重叠;再使用 memmove 保证数据不被破坏;最后打印数组,观察重叠拷贝结果。

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

2.3memmove的模拟实现

#include <assert.h>

void * my_memmove(void * dst, const void * src, size_t count)
{
	void * ret = dst;//保存目标地址
	assert(dst != NULL);
	assert(src != NULL);

	//情况1:不重叠,从前往后拷贝
	if (dst <= src || (char *)dst >= (char *)src + count)
	{
		while (count--)
		{
			*(char *)dst = *(char *)src;
			dst = (char *)dst + 1;
			src = (char *)src + 1;
		}
	}
	//情况2:重叠,从后往前拷贝
	else
	{
		//跳到最后一个字节开始拷贝
		dst = (char *)dst + count - 1;
		src = (char *)src + count - 1;
		while (count--)
		{
			*(char *)dst = *(char *)src;
			dst = (char *)dst - 1;
			src = (char *)src - 1;
		}
	}
	
	return ret;
}

🧐分析:首先判断地址关系,选择拷贝方向;当发现重叠时从后往前拷贝,避免覆盖源数据;因为是逐字节操作,兼容所有类型。

三.memset -----> 内存块按字节设置

3.1函数原型(包含功能,参数,返回值)

函数原型:

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

功能:

  1. ptr 指向的内存,按字节设置value
  2. 共设置 num 个字节。
  3. 头文件:<string.h>

参数:

  1. ptr:要设置的内存起始地址
  2. value:要设置的值(只取低 8 位,按字节设置)
  3. num:要设置的字节数

返回值:

返回 ptr 指向的内存起始地址

3.2举例

#include <stdio.h>
#include <string.h>

int main()
{
	char str[] = "hello world";
	memset(str, 'x', 6);
	printf("%s\n", str);
	
	return 0;
}

🧐分析:先对字符串前 6 字节批量赋值为 ‘x’;然后按字节修改,速度快,适合初始化。

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

四.memcmp -----> 内存块逐字节比较

4.1函数原型(包含功能,参数,返回值)

函数原型:

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

功能:

  1. 比较 ptr1ptr2 指向的内存块,逐字节比较前 num 个字节
  2. 不关心数据类型,只比较二进制值。
  3. 头文件:<string.h>

参数:

  1. ptr1:待比较内存块 1
  2. ptr2:待比较内存块 2
  3. num:要比较的字节数

返回值:

  1. >0 时:ptr1 > ptr2
  2. =0 时:ptr1 == ptr2
  3. <0 时:ptr1 < ptr2

4.2举例

#include <stdio.h>
#include <string.h>

int main()
{
	char buffer1[] = "DWgaOtP12df0";
	char buffer2[] = "DWGAOTP12DF0";
	int n = memcmp(buffer1, buffer2, sizeof(buffer1));
	if (n > 0)
		printf("'%s' 大于 '%s'\n", buffer1, buffer2);
	else if (n < 0)
		printf("'%s' 小于 '%s'\n", buffer1, buffer2);
	else
		printf("'%s' 与 '%s' 相同\n", buffer1, buffer2);

	return 0;
}

🧐分析:先逐字节比较两块内存区域;然后根据返回值判断大小关系。

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

🎯总结

1. memcpy:通用内存拷贝,以字节为单位复制数据,不支持内存重叠,但效率较高。
2. memmovepro版本内存拷贝,支持内存重叠,工程中更安全。
3. memset:以字节为单位初始化内存,常用于内存置 0、置字符。
4. memcmp:以字节为单位比较两块内存,不受 \0 结束符限制,可比较任意数据。
5. 四个函数均依赖头文件<string.h>,以 void* 为参数,支持任意数据类型操作

⚠️易错点

  1. memcpy 处理重叠内存,导致数据被覆盖、结果异常。
  2. memset 按字节赋值,误用给int数组设为 1,结果并非每个元素为 1
  3. 拷贝 / 比较时,字节数 num 计算错误,造成内存越界。
  4. 模拟实现时,未将 void* 强转为 char*,无法正确逐字节操作。
  5. 忘记使用 assert(断言) 校验指针合法性,传入空指针导致程序崩溃。
  6. 混淆 memcmpstrcmpmemcmp 不遇到 \0 停止,会严格比较 num个字节。
  7. 遗漏头文件<string.h>,导致函数未定义报错。

👀 关注 一路同行,从入门到大师,慢慢沉淀、稳步成长
❤️ 点赞 鼓励原创,让优质内容被更多人看见
⭐ 收藏 收好核心知识点与实战技巧,需要时随时查阅
💬 评论 分享你的疑问或踩坑经历,一起交流避坑、共同进步

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐