【深入详解】C语言内存函数:memcpy、memmove的使用和模拟实现,memset、memcmp函数的使用

article/2025/8/11 12:54:19

目录

一、memcpy、memmove使用和模拟实现

(一)memcpy的使用和模拟实现

1、代码演示: 

(1)memcpy拷贝整型

 (2)memcpy拷贝浮点型

2、模拟实现

(二)memmove的使用和模拟实现

1、代码实现 

(1)内存没有重叠

(2)内存重叠

2、模拟实现

二、memset、memcmp函数的使用

(一)memset函数的使用

1、代码实现

(1)针对字符数组

(2)针对整型数组

2、总结

(二)memcmp函数的使用

1、代码实现:

(1)比较前16个字节

(2)比较17个呢 

2、总结

结尾


🔥个人主页:艾莉丝努力练剑

🍓专栏传送门:《C语言》

🍉学习方向:C/C++方向

⭐️人生格言:为天地立心,为生民立命,为往圣继绝学,为万世开太平  


 


前言:前面几篇文章介绍了c语言的一些知识,包括循环、数组、函数、VS实用调试技巧、函数递归、操作符、指针、字符函数和字符串函数、结构体、联合和枚举、动态内存管理、文件操作、编译和链接、预处理等,在这篇文章中,我将开始介绍C语言内存函数的一些重要知识点!对C语言内存函数感兴趣的友友们可以在评论区一起交流学习!


一、memcpy、memmove使用和模拟实现

(一)memcpy的使用和模拟实现

memcmp:memory copy——内存拷贝;

代码原型:

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

三板斧——

功能:
(1)memcpy 是完成内存块拷贝的,不关注内存中存放的数据是什么;
(2)函数 memcpy source 的位置开始向后复制 num 个字节的数据到 destination 指向的内存
位置;
(3)如果 source destination 有任何的重叠,复制的结果都是未定义的 (内存重叠的情况使用memmove 就行)。
注: memcpy 的使用需要包含 <string.h>。
参数:
destination :指针,指向目标空间,拷贝的数据存放在这里;
source :指针,指向源空间,要拷贝的数据从这里来;
num :要拷贝的数据占据的字节数。
返回值:
拷贝完成后,返回目标空间的起始地址。
1、代码演示: 
(1)memcpy拷贝整型

strcpy、strncpy拷贝字符串的,是有局限性的;

拷贝一个整型数组呢?结构体数组呢?

#define  _CRT_SECURE_NO_WARNINGS  1#include<stdio.h>int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//             0 1 2 3 4 5...int arr2[20] = { 0 };//             0 1 2 3 4 5...//想把arr1中的10个整数,拷贝到arr2中//循环遍历//memcpymemcpy(arr2, arr1, 40);return 0;
}
 (2)memcpy拷贝浮点型
#include<stdio.h>int main()
{int arr1[] = { 1.2f,2.2f,3.2f,4.5f,5.5f };int arr2[20] = { 0 };memcpy(arr2, arr1, 5 * sizeof(float));return 0;
}
2、模拟实现
#include<stdio.h>void* my_memcpy(void* dest, const void* src, size_t num)
{void* ret = dest;assert(dest && src);while (num--){*(char*)dest = *(char*)src;src = (char*)src + 1;dest = (char*)dest + 1;}return ret;
}
//4*3 + 3int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };my_memcpy(arr2, arr1, 40);return 0;
}

那么我们可不可以把1,2,3,4,5这五个整型拷贝到3,4,5,6,7这五个整型的位置(覆盖了):

下面是我们自己写的代码演示:

#include<stdio.h>
#include<assert.h>void* my_memcpy(void* dest, const void* src, size_t num)
{void* ret = dest;assert(dest && src);while (num--){*(char*)dest = *(char*)src;src = (char*)src + 1;dest = (char*)dest + 1;}return ret;
}
//4*3 + 3int main()
{//int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//int arr2[20] = { 0 };//my_memcpy(arr2, arr1, 40);int arr[] = { 1,2,3,4,5,6,7,8,9,10 };my_memcpy(arr + 2, arr, 20);return 0;
}

我们发现达不到我们想要的效果。 

那索性就不要用my_memcpy了,下面是我们直接调用库里的函数实现的:

#include<stdio.h>
#include<assert.h>void* my_memcpy(void* dest, const void* src, size_t num)
{void* ret = dest;assert(dest && src);while (num--){*(char*)dest = *(char*)src;src = (char*)src + 1;dest = (char*)dest + 1;}return ret;
}
//4*3 + 3int main()
{//int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };//int arr2[20] = { 0 };//my_memcpy(arr2, arr1, 40);int arr[] = { 1,2,3,4,5,6,7,8,9,10 };memcpy(arr + 2, arr, 20);return 0;
}

监视打开: 

memcpy:不重叠的就可以了,memcpy连重叠的都能搞定。 

(二)memmove的使用和模拟实现

memmove:可以处理不重叠的,也可以处理重叠内存。

代码原型:

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

三板斧——

功能:
(1)memmove函数也是完成内存块拷贝的;
(2)和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
注: memmove的使用也需要包含<string.h>。
参数:
destination :指针,指向目标空间,拷贝的数据存放在这里;
source :指针,指向源空间,要拷贝的数据从这里来;
num :要拷贝的数据占据的字节数。
返回值:
拷贝完成后,返回目标空间的起始地址。
1、代码实现 
(1)内存没有重叠
#include<stdio.h>
#include<assert.h>int main()
{//内存没有重叠int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[20] = { 0 };//memcpy();memmove(arr2, arr1, 20);
}
(2)内存重叠
#include<stdio.h>
#include<assert.h>int main()
{//内存重叠int arr[] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr + 2, arr, 20);return 0;
}
2、模拟实现
#define  _CRT_SECURE_NO_WARNINGS  1#include<stdio.h>
#include<assert.h>
void * my_memmove(void* dest,void* src,size_t num)
{assert(dest && src);void* net = dest;if (dest < src){//前->后while (num--){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;}}else//2 3{while (num--){*((char*)dest + num) = *((char*)src + num);}}return net;
}
int main()
{//内存重叠int arr[] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr + 2, arr, 20);return 0;
}

二、memset、memcmp函数的使用

(一)memset函数的使用

代码原型:

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

三板斧——

功能:
memset 函数是用来设置内存块的内容的,将内存中指定长度的空间设置为特定的内容。
注: memset 的使用也需要包含 <string.h>。
参数:
ptr :指针,指向要设置的内存空间,也就是存放了要设置的内存空间的起始地址;
value :要设置的值,函数将会把 value 值转换成 unsigned char 的数据进行设置的,也就是以字节为单位来设置内存块的;
num :要设置的内存长度,单位是字节。
返回值:返回的是要设置的内存空间的起始地址。
1、代码实现
(1)针对字符数组
//针对字符数组
#include<stdio.h>
#include<string.h>int main()
{char arr[] = "hello world";memset(arr + 2, 'x', 5);printf("%s\n", arr);return 0;
}
(2)针对整型数组
#include<stdio.h>
#include<string.h>int main()
{int arr[10] = { 0 };//能否将arr的每个元素设置为1memset(arr, 1, 40);return 0;
}
2、总结
当有一块内存空间需要设置内容的时候,就可以使用memset函数,值得注意的是memset函数对内存单元的设置是以字节为单位的。

(二)memcmp函数的使用

代码原型:

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

三板斧—— 

功能:

比较指定的两块内存块的内容,比较从ptr1和ptr2指针指向的位置开始,向后的num个字节。

注:memcmp 的使用需要包含 <string.h>。

参数:

ptr1 :指针,指向一块待比较的内存块;

ptr2 :指针,指向另外⼀块待比较的内存块;

num :指定的比较长度,单位是字节。
返回值:
1、代码实现:
(1)比较前16个字节
#include<stdio.h>
#include<string.h>int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[] = { 1,2,3,4,8 };int r = memcmp(arr1, arr2, 16);if (r > 0)printf(">\n");else if (r < 0)printf("<\n");elseprintf("==\n");return 0;
}

打开内存,观察一下:

输出结果:

(2)比较17个呢 
#include<stdio.h>
#include<string.h>int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[] = { 1,2,3,4,8 };int r = memcmp(arr1, arr2, 17);if (r > 0)printf(">\n");else if (r < 0)printf("<\n");elseprintf("==\n");return 0;
}

打开内存,观察一下:

输出结果:

 

2、总结
(1)如果要比较2块内存单元的数据的大小,可以使用 memcmp 函数,这个函数的特点就是可以指定比较长度;
(2)memcmp 函数是通过返回值告知大小关系的。

结尾

往期回顾:

字符函数和字符串函数(二):strncpy、strncat、strncmp函数的使用、strstr的使用和模拟实现、strtok函数的使用、strerror函数的使用

字符函数和字符串函数(一):字符分类函数、字符转换函数、strlen的使用和模拟实现、strcpy的使用和模拟实现、strcat的使用和模拟实现、strcmp的使用和模拟实现

C语言指针深入详解(六):sizeof和strlen的对比,【题解】数组和指针笔试题解析、指针运算笔试题解析

结语:本篇文章就到此结束了,本文为友友们分享了C语言内存函数相关的一些重要知识点,如果友友们有补充的话欢迎在评论区留言,在这里感谢友友们的关注与支持!


http://www.hkcw.cn/article/BxEumTcbHG.shtml

相关文章

设计模式——责任链设计模式(行为型)

摘要 责任链设计模式是一种行为型设计模式&#xff0c;旨在将请求的发送者与接收者解耦&#xff0c;通过多个处理器对象按链式结构依次处理请求&#xff0c;直到某个处理器处理为止。它包含抽象处理者、具体处理者和客户端等核心角色。该模式适用于多个对象可能处理请求的场景…

软件的兼容性如何思考与分析?

软件功能的兼容性是指软件在实现功能的时候&#xff0c;能够与其他软件、硬件、系统环境以及数据格式等相互协作、互不冲突&#xff0c;并且能够正确处理不同来源或不同版本的数据、接口和功能模块的能力。它确保软件在多种环境下能够正常运行&#xff0c;同时与其他系统和用户…

C++ —— STL容器——string类

1. 前言 本篇博客将会介绍 string 中的一些常用的函数&#xff0c;在使用 string 中的函数时&#xff0c;需要加上头文件 string。 2. string 中的常见成员函数 2.1 初始化函数 string 类中的常用的初始化函数有以下几种&#xff1a; 1. string() …

DFS每日刷题

目录 P1605 迷宫 P1451 求细胞数量 P1219 [USACO1.5] 八皇后 Checker Challenge P1605 迷宫 #include <iostream> using namespace std; int n, m, t; int a[20][20]; int startx, starty, endx, endy; bool vis[20][20]; int res; int dx[] {0, 1, 0, -1}; int dy[]…

USART 串口通信全解析:原理、结构与代码实战

文章目录 USARTUSART简介USART框图USART基本结构数据帧起始位侦测数据采样波特率发生器串口发送数据 主要代码串口接收数据与发送数据主要代码 USART USART简介 一、USART 的全称与基本定义 英文全称 USART&#xff1a;Universal Synchronous Asynchronous Receiver Transmi…

C# winform 教程(一)

一、安装方法 官网下载社区免费版&#xff0c;在线下载安装 VS2022官网下载地址 下载后双击启动&#xff0c;选择需要模块&#xff08;net桌面开发&#xff0c;通用window平台开发&#xff0c;或者其他自己想使用的模块&#xff0c;后期可以修改&#xff09;&#xff0c;选择…

ZLG ZCANPro,ECU刷新,bug分享

文章目录 摘要 📋问题的起因bug分享 ✨思考&反思 🤔摘要 📋 ZCANPro想必大家都不陌生,买ZLG的CAN卡,必须要用的上位机软件。在汽车行业中,有ECU软件升级的需求,通常都通过UDS协议实现程序的更新,满足UDS升级的上位机要么自己开发,要么用CANoe或者VFlash,最近…

Matlab作图之 subplot

1. subplot(m, n, p) 将当前图形划分为m*n的网格&#xff0c;在 p 指定的位置创建坐标轴 matlab 按照行号对子图的位置进行编号 第一个子图是第一行第一列&#xff0c;第二个子图是第二行第二列......... 如果指定 p 位置存在坐标轴&#xff0c; 此命令会将已存在的坐标轴设…

【STM32F1标准库】理论——外部中断

目录 一、中断介绍 二、外部引脚EXTI申请的中断 三、外部中断的适用场景 四、其他注意事项 一、中断介绍 STM32可以触发中断的外设有外部引脚(EXTI)、定时器、ADC、DMA、串口、I2C、SPI等 中断同一由NVIC管理 n表示一个外设可能同时占用多个中断通道 优先级的值越小优先…

SAP学习笔记 - 开发18 - 前端Fiori开发 应用描述符(manifest.json)的用途

上一章讲了 Component配置&#xff08;组件化&#xff09;。 本章继续讲Fiori的知识。 目录 1&#xff0c;应用描述符(Descriptor for Applications) 1&#xff09;&#xff0c; manifest.json 2&#xff09;&#xff0c;index.html 3&#xff09;&#xff0c;Component.…

定时任务:springboot集成xxl-job-core(一)

springboot:2.7.2 xxl-job-core: 2.3.0 一、集成xxl-job 1. 在gitee上下载xxl-job项目 git clone https://gitee.com/xuxueli0323/xxl-job.git 2. 执行以下目录下的sql /xxl-job-2.3.0/doc/db/tables_xxl_job.sql 3. 在xxl-job-admin的项目中配置数据库信息 ### xxl-job, data…

【STM32开发板】接口部分

一、USB接口 可以看到USBP和USBN与PA12,PA11引脚相接,根据协议&#xff0c;需要添加上拉电阻 二、ADC和DAC 根据原理图找到可以作为ADC和DAC的引脚 ADC和DAC属于模拟部分的&#xff0c;所以要接模拟地 三、指示灯电路 找几个通用的引脚&#xff0c;因为单片机的灌电流比拉电流…

阻塞队列BlockingQueue解析

阻塞队列是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除的方法。 阻塞插入&#xff1a;当队列满的时候&#xff0c;队列会阻塞插入元素的线程&#xff0c;直到队列不满。 阻塞移除&#xff1a;当队列空的时候&#xff0c;队列会阻塞移除元素的线程&…

[Redis] Redis命令在Pycharm中的使用

初次学习&#xff0c;如有错误还请指正 目录 String命令 Hash命令 List命令 set命令 SortedSet命令 连接pycharm的过程见&#xff1a;[Redis] 在Linux中安装Redis并连接桌面客户端或Pycharm-CSDN博客 redis命令的使用见&#xff1a;[Redis] Redis命令&#xff08;1&#xf…

车载控制器的“机电一体化”深度集成

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 所谓鸡汤&#xff0c;要么蛊惑你认命&#xff0c;要么怂恿你拼命&#xff0c;但都是回避问题的根源&…

PINN模型相关原理

PINN模型相关原理 目录 PINN模型相关原理原本的物理界的利用神经网络的参数估计PINN 的原理介绍一、基本思想二、PINN 的损失函数三、自动微分&#xff08;Autodiff&#xff09;四、PINN 的优势与挑战 原本的物理界的利用神经网络的参数估计 原本物理界需要确定一个三维流体&a…

计算机基础——宏病毒防御与网络技术

文章目录 宏病毒详解与防范措施宏病毒简介宏病毒的特点宏病毒的传播途径宏病毒的防范措施宏病毒的检测与清除 自治计算机与自治系统解析什么是自治计算机&#xff1f;技术特点 自治系统&#xff08;Autonomous System, AS&#xff09;特点&#xff1a;自治系统类型 总结&#x…

MySql(十一)

目录 准备工作 1&#xff09;准备一张表 2&#xff09;插入数据 分组 1&#xff09;通过性别去统计各组的平局工资 2.limit关键字 不使用limit的关键字 使用limit的关键字 使用limit关键字获取从指定行开始获取 准备工作 1&#xff09;准备一张表 CREATE table role(roleid INT…

论文阅读(六)Open Set Video HOI detection from Action-centric Chain-of-Look Prompting

论文来源&#xff1a;ICCV&#xff08;2023&#xff09; 项目地址&#xff1a;https://github.com/southnx/ACoLP 1.研究背景与问题 开放集场景下的泛化性&#xff1a;传统 HOI 检测假设训练集包含所有测试类别&#xff0c;但现实中存在大量未见过的 HOI 类别&#xff08;如…

使用 SASS 与 CSS Grid 实现鼠标悬停动态布局变换效果

最终效果概述 页面为 3x3 的彩色格子网格&#xff1b;当鼠标悬停任意格子&#xff0c;所在的行和列被放大&#xff1b;使用纯 CSS 实现&#xff0c;无需 JavaScript&#xff1b;利用 SASS 的模块能力大幅减少冗余代码。 HTML 结构 我们使用非常基础的结构&#xff0c;9 个 .i…