【C语言进阶】内存函数
天生我材必有用,千金散尽还复来。 ——李白
目录
前言
一.memcpy函数
1.实现memcpy函数
2.模拟实现memcpy函数
二.memmove函数
1.实现memmove函数
2.模拟实现memmove函数
三.memcpy函数和memmove函数的关系
四.memcmp函数
1.实现memcmp函数
2.模拟实现memcmp函数
五.memset函数
前言
上次我们学习了字符串函数:strcpy,strcat,strcmp等等字符串函数,顾名思义这些字符串函数只能对字符串进行一系列的操作,而不能对整型,浮点型之类的内容进行操作。
今天我们就要学习内存函数:memcpy,memmove,memcmp等等内存函数。前缀mem就是英文里面的memory单词的意思,而memory在计算机里面理解为内存,所以这些函数是对内存进行操作,不会被类型所限制,可以操作各种各样的类型。
一.memcpy函数

void *memcpy( void *dest, const void *src, size_t count ),这里为什么要用void*的指针呢?
因为这是一个内存函数,我们可以操作各种的数据类型,void*的指针可以接收任何类型的指针。在要使用的时候,只需要将void*强制类型转换即可达到目的。
1.实现memcpy函数
#include<stdio.h>
#include<string.h>//内存函数的头文件
int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };memcpy(arr2, arr1, 20);//20也就是20个字节,即拷贝5个整型int i = 0;for (i = 0; i < 5; i++){printf("%d ", arr2[i]);}return 0;
}
2.模拟实现memcpy函数
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);void* start = dest;while (num)//一共20个字节{*(char*)dest = *(char*)src;//一个一个字节的进行拷贝dest = (char*)dest + 1;src = (char*)src + 1;num--;//直到num为0个字节时,即拷贝结束}return start;
}
int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };my_memcpy(arr2, arr1, 20);//20也就是20个字节,即拷贝5个整型int i = 0;for (i = 0; i < 5; i++){printf("%d ", arr2[i]);}return 0;
}

当我们要把自己数组的内容给拷贝的自己的数组内容上会发生什么?
void* my_memcpy(void* dest, const void* src, size_t num)
{assert(dest && src);void* start = dest;while (num)//一共20个字节{*(char*)dest = *(char*)src;//一个一个字节的进行拷贝dest = (char*)dest + 1;src = (char*)src + 1;num--;//直到num为0个字节时,即拷贝结束}return start;
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };my_memcpy(arr+2, arr, 20);//在一个数组里面操作int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}
我们的目的是arr数组里面的3 4 5 6 7改为1 2 3 4 5,结果应该是1 2 1 2 3 4 5 8 9 10。结果是什么呢?让我们一起来看看。

结果为什么是这样呢?我们不妨通过画图来理解一下,在做题时,画图时非常重要的。

这里就是有重叠的部分,在对于有重叠的部分 ,我们使用memmove函数。
二.memmove函数
1.实现memmove函数
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr+2, arr, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

2.模拟实现memmove函数
void* my_memmove(void* dest, void* src, size_t num)
{assert(dest && src);void* start = dest;while (num){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;num--;}return start;
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr+2, arr, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

为什么又是这样,到这里可能人都要被气成sb,但是我们要心平气和,继续我们的画图来好好的来理解一下。
正确的代码:
void* my_memmove(void* dest, void* src, size_t num)
{assert(dest && src);void* start = dest;if(dest>src){while (num--){*((char*)dest + num) = *((char*)src + num);}}else{while (num){*(char*)dest = *(char*)src;dest = (char*)dest + 1;src = (char*)src + 1;num--;}}return start;
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr+2, arr, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

三.memcpy函数和memmove函数的关系
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };memcpy(arr + 2, arr, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

这里可以看出数组即使有重叠的部分 ,但是memcpy函数一样的可以实现和memmove函数一样的功能。我们可以这样理解:其实memcpy函数是memmove函数的一个子函数。
在vs平台上memcpy函数和memmove的功能一模一样,但是并不保证在其他平台上面两个函数的功能是一样的。
总结:在有重叠部分的时候都用memmove函数。没重叠部分的,两个函数用谁都行。
四.memcmp函数
1.实现memcmp函数
memcmp函数也是一个字节一个字节的进行比较。同样和strcmp函数一样,最后比较的是ASCll码值。

int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 1,2,3,4,5,7 };int ret=memcmp(arr1, arr2, 20);printf("%d\n", ret);return 0;
}

比较21字节会是怎么样呢?
int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 1,2,3,4,5,7 };int ret=memcmp(arr1, arr2, 21);//比较21字节会是怎么样呢?//前20个字节都相等,这是毋庸置疑的的//6的小端字节序:06 00 00 00//7的小端字节序:07 00 00 00//很明显7的第一个字节大于6,即arr2大于arr1,返回-1printf("%d\n", ret);return 0;
}
2.模拟实现memcmp函数
模拟实现memcmp函数和模拟实现strcmp函数是非常相似的。
int my_memcmp(const void* buf1, const void* buf2, size_t num)
{assert(buf1 && buf2);size_t m = num;while (num--){if (*(char*)buf1 == *((char*)buf2)){buf1 = (char*)buf1 + 1;buf2 = (char*)buf2 + 1;}elsereturn (*(char*)buf1 - *((char*)buf2));}return 0;//退出循环都没有return,那么就说明两个是相等的。
}
int main()
{int arr1[10] = { 1,2,4,4,5,6,7,8,9,10 };int arr2[10] = { 1,2,5 };int ret = my_memcmp(arr1, arr2, 9);//比较9个字节if (ret == -1){printf("arr1小于arr2\n");}else if (ret == 1){printf("arr1大于arr2\n");}elseprintf("arr1和arr2相等\n");return 0;
}

五.memset函数
void *memset(void *str, int c, size_t n)
//str -- 指向要填充的内存块。
//c -- 要被设置的值。该值以 int 形式传递,但是函数在填充内存块时是使用该值的无符号字符形式。
//n -- 要被设置为该值的字符数。
代码实现:
int main()
{char arr[20] = "hello world";memset(arr, '*', 5);//将arr的前五个字节改为*printf("%s\n", arr);
}

如果我们要对整数进行操作呢?
int main()
{int arr[10] = { 1,2,3,4,5 };memset(arr, 1, 8);//操作8个字节int i = 0;for (i = 0; i < 5; i++){printf("%d ", arr[i]);}return 0;
}

这里为什么为得到这么奇怪的数字呢?
注意:memset是一个一个字节的进行操作,而int是4个字节为一个数字。
如:1的小端字节序是 01 00 00 00,然后一个一个字节的改为1,最后就成了 01 01 01 01,
16进制的01010101就是16843009。

所以memset不能随便用,有可能会带来不一样的结果。要根据实际情况来使用。
感谢老铁们的支持。
相关文章:
【C语言进阶】内存函数
天生我材必有用,千金散尽还复来。 ——李白 目录 前言 一.memcpy函数 1.实现memcpy函数 2.模拟实现memcpy函数 二.memmove函数 1.实现memmove函数 2.模拟实现memmove函数 三.memcpy函数和memmove函数的关系 四.memcm…...
Java开发 - ELK初体验
前言 前面我们讲过消息队列,曾提到消息队列也具有保存消息日志的能力,今天要说的EL看也具备这个能力,不过还是要区分一下功能的。消息队列的日志主要指的是Redis的AOF,实际上只是可以利用了消息队列来保存,却并不是消…...
AI_Papers周刊:第六期
CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 2023.03.13—2023.03.19 文摘词云 Top Papers Subjects: cs.CL 1.UPRISE: Universal Prompt Retrieval for Improving Zero-Shot Evaluation 标题:UPRISE:改进零样本评估…...
JS运行环境、包管理、打包工具总结
🌳JS运行环境-node.js 运行环境就是代码解析和执行的程序,比如jvm等虚拟机,他们的主要工作就是根据设定的语法规则解析编译代码,然后运行代码。 js的语法规则遵循ES规范。 🍁node.js Node.Js官网 Node.js是一种基于Ch…...
day4网络编程(广播和组播)
1.广播 发送端(类似于客户端) 流程: 创建套接字 填充接收端(服务器)网络信息结构体 bind(非必须绑定) 设置允许广播 向接收端(服务器)发送数据 关闭套接字文件 #include <stdio.h> #in…...
Vue3 自动引入组件及函数、动态生成侧边栏路由
Vue3 自动引入组件及函数、动态生成侧边栏路由 1、安装依赖 npm install -D unplugin-auto-import unplugin-icons unplugin-vue-components插件使用说明 unplugin-auto-import 说明 —— 自动引入函数、组件 unplugin-vue-components 说明 —— 自动注册组件 unplugin-ic…...
人工智能交互系统界面设计
文章目录前言一、项目介绍二、项目准备三、项目实施1.导入相关库文件2.人脸信息验证功能3.语音交互与TCP数据通信4.数据信息可视化四、相关附件前言 在现代信息化时代,图形化用户界面(Graphical User Interface, GUI)已经成为各种软件应用和…...
蓝桥杯嵌入式第一课--创建工程
概述学习本节之前,必须要先安装好 keil5 以及 CubeMX 等软硬件环境,如果你已经安装完成,请告诉自己:考试现在开始!从CubeMX开始CubeMX是创建工程模板的软件,也是我们比赛时第一个要进行操作的软件。一、选择…...
Java面向对象:接口的学习
本文介绍了Java中接口的基本语法, 什么是接口, java中的接口 语法规则, 接口的使用,接口的特性,如何实现多个接口,接口间的继承,以及抽象类和接口的区别 Java接口的学习一.接口的概念二.Java中的接口1.接口语法规则2.接口的使用3.接口的特性4.实现多个接口5.接口间的继承三.抽象…...
西瓜视频登录页面
题目 代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>登录页面</title><style>td{width: 160px;height: 25px;}img{width: 20px;height: 20px;}.number, .password{background: rgba(0,0,0,.05);}.numbe…...
【springboot】常用快捷键:
Ctrl快捷键介绍Ctrl F在当前文件进行文本查找 (必备)Ctrl R在当前文件进行文本替换 (必备)Ctrl Z撤销 (必备)Ctrl Y删除光标所在行 或 删除选中的行 (必备)Ctrl X剪切光标所在行…...
宝塔控制面板常用Linux命令大全
宝塔面板是站长朋友们常见的一款服务器运维面板,可以通过 Web 端轻松管理服务器,提升运维效率。大家在服务器中安装宝塔面板会用到宝塔面板特定的脚本命令。今天这篇文章为大家整理汇总了宝塔面板常用Linux命令,这样方便大家收藏查找。 1、安…...
C语言实现单链表(超多配图,这下不得不学会单链表了)
目录 一:什么是链表? 二:创建源文件和头文件 (1)头文件 (2)源文件 三:实参和形参 四:一步步实现单向链表 (1)建立一个头指针并置空 (2)打印链表,便于…...
SQL编写优化技巧
一、底层原理 sql慢是因为没有走索引,因此需要添加索引然它走索引联合索引需要匹配最左匹配原则(索引回表)如果查询列超出索引的key, 会导致回表,回表数量多,则会走全表扫描 索引是分聚集索引、非聚集索引…...
【基础算法】单链表的OJ练习(6) # 复制带随机指针的链表 #
文章目录🍇前言🍎复制带随机指针的链表🍑写在最后🍇前言 本章的链表OJ练习,是最后的也是最难的。对于本题,我们不仅要学会解题的思路,还要能够通过这个思路正确的写出代码,也就是思路…...
Activity生命周期完成EvenetLog回调
Activity 生命周期 系统EvenetLog回调 EventLog路径: Android13/frameworks/base/core/java/android/app/EventLogTags.logtags wm_on_create_called wm_on_restart_called wm_on_start_called wm_on_resume_called wm_on_top_resumed_gained_called wm_on_top_resumed_lost_c…...
西安石油大学C语言期末真题实战
很简单的一道程序阅读题,pa’默认为a【0】,接下来会进行3次循环 0 1 2 输出结果即可 前3题就是一些基础定义,在此不多赘述 要注意不同的数据类型的字节数不同 a<<2 b>>1(b>>1;就是说b自身右位移一位(…...
【Shell】Shell变量
Shell变量系统预定义变量自定义变量基本语法定义变量撤销变量命名规则使用变量只读变量删除变量变量类型系统预定义变量 $HOME、$PWD、$SHELL、$SUSER等 实例 yysubuntu:~$ echo $HOME #查看系统变量的值 /home/yys yysubuntu:~$ set #显示当前shell中所有变量自定义变量…...
你是真的“C”——结构体中鲜有人知的“秘密”
你是真的“C”——结构体中的精髓剖析【内存对齐】 【位段】 😎前言🙌结构体内存对齐:😊结构体内存对齐存在的意思是什么?😘内存对齐例子详细剖析:😘结构体中的位段:&…...
2023年“网络安全”赛项江苏省淮安市赛题解析(超详细)
2023年中职组江苏省淮安市“网络空间安全”赛项 ①.2023年中职组江苏省淮安市任务书②.2023年中职组江苏省淮安市解析③.需要环境或者不懂的可以私信博主!①.2023年中职组江苏省淮安市任务书 任务一:服务器内部信息获取 任务环境说明: 服务器场景:Server210510(关闭链接…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
12.找到字符串中所有字母异位词
🧠 题目解析 题目描述: 给定两个字符串 s 和 p,找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义: 若两个字符串包含的字符种类和出现次数完全相同,顺序无所谓,则互为…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
OPenCV CUDA模块图像处理-----对图像执行 均值漂移滤波(Mean Shift Filtering)函数meanShiftFiltering()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 在 GPU 上对图像执行 均值漂移滤波(Mean Shift Filtering),用于图像分割或平滑处理。 该函数将输入图像中的…...
MySQL 部分重点知识篇
一、数据库对象 1. 主键 定义 :主键是用于唯一标识表中每一行记录的字段或字段组合。它具有唯一性和非空性特点。 作用 :确保数据的完整性,便于数据的查询和管理。 示例 :在学生信息表中,学号可以作为主键ÿ…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
libfmt: 现代C++的格式化工具库介绍与酷炫功能
libfmt: 现代C的格式化工具库介绍与酷炫功能 libfmt 是一个开源的C格式化库,提供了高效、安全的文本格式化功能,是C20中引入的std::format的基础实现。它比传统的printf和iostream更安全、更灵活、性能更好。 基本介绍 主要特点 类型安全:…...
在golang中如何将已安装的依赖降级处理,比如:将 go-ansible/v2@v2.2.0 更换为 go-ansible/@v1.1.7
在 Go 项目中降级 go-ansible 从 v2.2.0 到 v1.1.7 具体步骤: 第一步: 修改 go.mod 文件 // 原 v2 版本声明 require github.com/apenella/go-ansible/v2 v2.2.0 替换为: // 改为 v…...
大数据治理的常见方式
大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法,以下是几种常见的治理方式: 1. 数据质量管理 核心方法: 数据校验:建立数据校验规则(格式、范围、一致性等)数据清洗&…...
MySQL体系架构解析(三):MySQL目录与启动配置全解析
MySQL中的目录和文件 bin目录 在 MySQL 的安装目录下有一个特别重要的 bin 目录,这个目录下存放着许多可执行文件。与其他系统的可执行文件类似,这些可执行文件都是与服务器和客户端程序相关的。 启动MySQL服务器程序 在 UNIX 系统中,用…...

