news 2026/5/30 15:12:47

C 语言的内存函数:memcpy/memmove/memset/memcmp 精讲(含模拟实现)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C 语言的内存函数:memcpy/memmove/memset/memcmp 精讲(含模拟实现)

🏠个人主页:黎雁
🎬作者简介:C/C++/JAVA后端开发学习者
❄️个人专栏:C语言、数据结构(C语言)、EasyX、游戏、规划
✨ 从来绝巘须孤往,万里同尘即玉京

文章目录

    • 前景回顾:字符串函数核心速记 📝
    • 一、memcpy:不重叠内存的拷贝神器 📤
      • 1. 函数核心要点(<string.h>)
      • 2. 实战示例:拷贝整型数组
      • 3. 模拟实现:逐字节拷贝
      • 4. 注意事项:重叠内存的坑 ❗
    • 二、memmove:处理重叠内存的升级版 🔄
      • 1. 函数核心要点(<string.h>)
      • 2. 核心思路:分情况选择拷贝方向
      • 3. 模拟实现:双向拷贝逻辑
    • 三、memset:按字节设置内存值 🎨
      • 1. 函数核心要点(<string.h>)
      • 2. 正确用法:设置字符数组
      • 3. 经典踩坑:设置非字符类型数组 ❌
    • 四、memcmp:按字节比较内存区域 🆚
      • 1. 函数核心要点(<string.h>)
      • 2. 实战示例:比较整型数组
    • 写在最后 📝

字符串专题收官之后,我们迎来C语言内存操作的核心内容!这一篇聚焦四大内存函数——memcpy(内存拷贝)、memmove(内存移动)、memset(内存设置)、memcmp(内存比较),详解它们的使用规则、核心差异和模拟实现逻辑,帮你吃透以字节为单位的内存操作底层原理!

前景回顾:字符串函数核心速记 📝

C 语言字符串入门:字符函数 + strlen 精讲(从使用到模拟实现)
C 语言字符串进阶:strcpy/strcat/strcmp 精讲
C 语言字符串高阶:strstr/strtok/strerror 精讲(含 strstr 模拟实现)

回顾字符串函数的核心特性,能帮我们更好理解内存函数的设计逻辑:

  1. 字符串函数依赖\0作为终止标志,仅能处理字符类型数据。
  2. 内存函数不关心数据类型,以字节为单位操作内存,通用性更强。
  3. 模拟实现库函数时,assert断言指针非空是保证代码健壮性的必备操作。

一、memcpy:不重叠内存的拷贝神器 📤

memcpy的全称是memory copy,作用是从源内存地址拷贝指定字节数的数据到目标内存地址,和字符串函数strcpy不同,它不会因为遇到\0而停止

1. 函数核心要点(<string.h>)

  • 函数原型
    void*memcpy(void*destination,constvoid*source,size_tnum);
    • destination:目标内存起始地址
    • source:源内存起始地址
    • num:需要拷贝的字节数
  • 核心特性
    ✅ 不关心内存中存储的数据类型,逐字节拷贝
    ✅ 遇到\0不会停止,严格按照num指定的字节数拷贝
    仅适用于不重叠的两块内存区域

2. 实战示例:拷贝整型数组

#include<stdio.h>#include<string.h>intmain(){intarr1[]={1,2,3,4,5};// 占 5*4=20 字节intarr2[10]={0};// 拷贝arr1的20个字节到arr2memcpy(arr2,arr1,20);// 打印arr2:1 2 3 4 5 0 0 0 0 0for(inti=0;i<10;i++)printf("%d ",arr2[i]);return0;}

3. 模拟实现:逐字节拷贝

memcpy的模拟实现核心是强转为char*类型,因为char*每次操作正好是1个字节,完美匹配内存函数的设计逻辑。

#include<stdio.h>#include<assert.h>void*my_memcpy(void*dest,constvoid*src,size_tnum){assert(dest&&src);// 断言指针非空void*ret=dest;// 保存目标起始地址,用于返回// 逐字节拷贝while(num--){*(char*)dest=*(char*)src;src=(char*)src+1;dest=(char*)dest+1;}returnret;}// 测试代码intmain(){intarr1[]={1,2,3,4,5,6,7,8,9,10};intarr2[10]={0};my_memcpy(arr2,arr1,20);// 拷贝前5个整型元素for(inti=0;i<10;i++)printf("%d ",arr2[i]);return0;}

4. 注意事项:重叠内存的坑 ❗

如果用my_memcpy处理重叠内存,会出现数据覆盖问题:

// 错误案例:拷贝重叠区域intarr[]={1,2,3,4,5,6,7,8,9,10};// 想把 {3,4,5,6,7} 拷贝到 {1,2,3,4,5} 的位置my_memcpy(arr,arr+2,20);// 实际输出:{3,4,3,4,3,6,7,8,9,10} → 数据被覆盖

原因是my_memcpy从前往后拷贝,先拷贝的内容会覆盖后面待拷贝的数据。

💡 补充:VS2022等编译器对memcpy做了优化,能处理重叠内存,但标准C规定memcpy只负责不重叠内存,跨平台开发时要严格遵守标准,重叠内存请用memmove

二、memmove:处理重叠内存的升级版 🔄

memmove的全称是memory move,它是memcpy的增强版,支持重叠内存区域的拷贝,是实际开发中更安全的选择。

1. 函数核心要点(<string.h>)

  • 函数原型
    void*memmove(void*destination,constvoid*source,size_tnum);
    参数含义和memcpy完全一致。
  • 核心优势
    ✅ 兼容重叠内存和不重叠内存的拷贝
    ✅ 底层通过判断拷贝方向(从前往后/从后往前)避免数据覆盖

2. 核心思路:分情况选择拷贝方向

我们以数组{1,2,3,4,5,6,7,8,9,10}为例,分析destsrc的位置关系,确定拷贝方向:

内存位置关系拷贝方向原因
dest <= src(目标在源左边)从前往后先拷贝的内容不会覆盖待拷贝数据
dest > src(目标在源右边)从后往前避免先拷贝的内容覆盖后面的数据

3. 模拟实现:双向拷贝逻辑

#include<stdio.h>#include<assert.h>void*my_memmove(void*dest,constvoid*src,size_tnum){assert(dest&&src);void*ret=dest;if(dest<=src)// 情况1:目标在源左边 → 从前往后拷贝{while(num--){*(char*)dest=*(char*)src;src=(char*)src+1;dest=(char*)dest+1;}}else// 情况2:目标在源右边 → 从后往前拷贝{while(num--){// 从最后一个字节开始拷贝*((char*)dest+num)=*((char*)src+num);}}returnret;}// 测试重叠内存拷贝intmain(){intarr[]={1,2,3,4,5,6,7,8,9,10};// 把 {3,4,5,6,7} 拷贝到 {1,2,3,4,5} 的位置my_memmove(arr,arr+2,20);// 正确输出:3 4 5 6 7 6 7 8 9 10for(inti=0;i<10;i++)printf("%d ",arr[i]);return0;}

三、memset:按字节设置内存值 🎨

memset的全称是memory set,作用是以字节为单位,将指定内存区域的每个字节都设置为目标值。它是初始化内存的常用工具,但极易因使用不当踩坑。

1. 函数核心要点(<string.h>)

  • 函数原型
    void*memset(void*ptr,intvalue,size_tnum);
    • ptr:要设置的内存起始地址
    • value:要设置的字节值(虽然参数是int,但实际只取低8位)
    • num:要设置的字节数
  • 核心特性
    ✅ 逐字节设置值,不是逐元素
    ✅ 常用于初始化字符数组,或把内存置为0

2. 正确用法:设置字符数组

#include<stdio.h>#include<string.h>intmain(){chararr[]="hello world";// 从第3个字符开始,连续设置5个字节为 'x'memset(arr+2,'x',5);printf("%s\n",arr);// 输出:hexxxxxldreturn0;}

3. 经典踩坑:设置非字符类型数组 ❌

很多人会用memset初始化整型数组,结果和预期不符:

#include<stdio.h>#include<string.h>intmain(){intarr[]={1,2,3,4,5,6,7,8,9,10};// 想把数组每个元素设为1 → 实际是每个字节设为1memset(arr,1,40);// 数组占 10*4=40 字节return0;}

内存监视结果:每个整型元素的4个字节都被设为0x01,因此每个元素的值是0x01010101(十进制 16843009),完全不是预期的1!

💡 结论:memset仅适合设置单字节数据(如char),或把内存置为0(value=0时,任何类型元素都是0)。

四、memcmp:按字节比较内存区域 🆚

memcmp的全称是memory compare,作用是以字节为单位,比较两块内存区域的前num个字节。它和strcmp的区别是:不依赖\0,可比较任意类型数据。

1. 函数核心要点(<string.h>)

  • 函数原型
    intmemcmp(constvoid*ptr1,constvoid*ptr2,size_tnum);
    • ptr1/ptr2:要比较的两块内存起始地址
    • num:要比较的字节数
  • 返回值规则
    ▶ 若ptr1 > ptr2→ 返回大于0的值
    ▶ 若ptr1 == ptr2→ 返回0
    ▶ 若ptr1 < ptr2→ 返回小于0的值

2. 实战示例:比较整型数组

#include<stdio.h>#include<string.h>intmain(){intarr1[]={1,2,3,4,5};// 内存布局:01 00 00 00 02 00 00 00 ...intarr2[]={1,2,3,4,0x12333301};// 第5个元素内存:01 33 33 12// 比较前17个字节(前4个元素+第5个元素的第1个字节)intr=memcmp(arr1,arr2,17);printf("%d\n",r);// 输出:正数(arr1第17字节是05,arr2是01)return0;}

写在最后 📝

内存操作函数是C语言直接操控内存的核心工具,和字符串函数相比,它们的通用性更强,适用范围更广,但也更容易因忽视字节操作的特性而踩坑。

掌握这些函数的关键在于三点:

  1. 区分memcpymemmove的使用场景(重叠/不重叠内存);
  2. 牢记memset逐字节设置,而非逐元素;
  3. 理解memcmp的比较规则是基于字节的ASCII码值。

这些函数的模拟实现逻辑,也是笔面试中考察指针和内存操作的高频考点,建议大家手动敲一遍代码,加深对底层原理的理解。至此,C语言字符串和内存操作的核心内容就全部讲解完毕啦!

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/30 9:21:55

FPGA基础知识(二十一):xilinx FPGA中常用的原语

《FPGA基础知识》系列导航 本专栏专为FPGA新手打造的Xilinx平台入门指南。旨在手把手带你走通从代码、仿真、约束到生成比特流并烧录的全过程。 本篇是该系列的第二十一篇内容 上一篇&#xff1a;FPGA基础知识&#xff08;二十&#xff09;&#xff1a;Xilinx Block Memory I…

作者头像 李华
网站建设 2026/5/28 15:48:36

语雀文档批量导出神器:轻松实现完整内容迁移

语雀文档批量导出神器&#xff1a;轻松实现完整内容迁移 【免费下载链接】yuque-exporter 项目地址: https://gitcode.com/gh_mirrors/yuqu/yuque-exporter 还在为语雀文档迁移而烦恼吗&#xff1f;这款强大的语雀文档导出工具能够帮你快速完成批量迁移&#xff0c;将珍…

作者头像 李华
网站建设 2026/5/29 18:05:22

基于SpringBoot高校迎新管理系统(毕设源码+文档)

课题说明本课题聚焦高校迎新工作流程繁琐、信息传递不及时及数据统计低效等痛点&#xff0c;设计并实现基于SpringBoot的高校迎新管理系统。系统依托SpringBoot框架的高效稳定与易拓展优势&#xff0c;整合新生信息管理、报到流程管控、资源调度协调等核心场景&#xff0c;涵盖…

作者头像 李华
网站建设 2026/5/20 21:57:10

SGrid 创建和可视化一个带有矢量数据(Vector Data)的 3D 结构化网格

一&#xff1a;主要的知识点 1、说明 本文只是教程内容的一小段&#xff0c;因博客字数限制&#xff0c;故进行拆分。主教程链接&#xff1a;vtk教程——逐行解析官网所有Python示例-CSDN博客 2、知识点纪要 本段代码主要涉及的有①vtkHedgeHog将数据关联到网格上的顶点 二…

作者头像 李华
网站建设 2026/5/29 7:04:17

9个降AI率工具推荐!专科生高效避坑指南

9个降AI率工具推荐&#xff01;专科生高效避坑指南 AI降重工具&#xff0c;让论文更“自然” 在当今学术写作中&#xff0c;越来越多的专科生开始使用AI工具辅助完成论文写作。然而&#xff0c;随之而来的AIGC率过高、AI痕迹明显等问题也成为了困扰学生们的难题。如何在保证内容…

作者头像 李华
网站建设 2026/5/22 14:07:19

YOLOv8改进 - 注意力机制 | SEAM (Spatially Enhanced Attention Module) 空间增强注意力模块提升遮挡目标特征学习能力

前言 本文提出基于单阶段检测器YOLOv5的实时人脸检测器YOLO - FaceV2&#xff0c;并将SEAM模块集成到YOLOv8中。传统人脸检测算法在精度、速度及处理遮挡等问题上存在不足。SEAM模块采用多头注意力机制&#xff0c;通过深度可分离卷积、1x1卷积、全连接网络学习面部特征&#…

作者头像 李华