【C语言】内存函数的详细教学和模拟实现

🚀write in front🚀
🔎大家好,我是gugugu。希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
🆔本文由 gugugu 原创 CSDN首发🐒 如需转载还请通知⚠
📝个人主页:gugugu—精品博客
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​
📣系列专栏:gugugu的精品博客
✉️我们并非登上我们所选择的舞台,演出并非我们所选择的剧本📩

在这里插入图片描述
vs 启动

前言

上一篇博客里讲到了字符函数和字符串函数,那么在这一篇博客中,我们将另一种常见的函数讲解一下,就是内存函数,内存函数比字符函数和字符串函数更加的广泛,毕竟是针对内存的函数。
在这里插入图片描述

一、内存函数与字符串函数的区别

C语言内存函数,是针对内存块的,不在乎内存中的数据,但是字符串函数时针对字符串的,在乎内存中的数据,只操作字符串,与\0操作符关系密切。

二、memcpy函数

memcpy函数与strcpy函数功能比较相似,都是进行拷贝操作,但是memcpy针对的对象不同。

1、memcpy函数的基本结构

void* memcpy(void * destination ,const void * source,size_t num);
函数有三个参数,分别为起始地址,目标地址和移动的字节的大小,返回值是void*

  • 那么为什么起始地址和目标地址,以及返回值都是void类型呢?

在这里插入图片描述

因为memcpy函数针对的对象是内存空间,而内存空间中储存的数据类型不清楚,有多种可能性,所以直接使用void*类型的指针,在使用时,进行强制类型转换。

另外,在这里补充一点
在上一篇文章里面,很多字符串函数的返回值都是一个指针,这是为什么呢?

在这里插入图片描述

其实,这是为了能够通过返回值去更方便的进行链式访问

2、memcpy函数的模拟实现

在模拟实现memcpy这些内存函数的时候,主要是要注意对void*的强转,这比较巧妙。

这里提供两种方法。大同小异
方法一

#include <stdio.h>
#include <assert.h>void* my_memcpy(void* ch1, const void* ch2, size_t num)
{assert(ch1 && ch2);void* ret = ch1;int i = 0;for (i = 0; i < num; i++){*((char*)ch1)++ = *((char*)ch2)++;}return ret;
}int main()
{int arr1[10] = { 0 };int arr2[] = { 1,2,3,4,5,6,7,8 };
void * ret1=my_memcpy(arr1, arr2, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(((int*)ret1)++));}printf("\n");char ch1[] = "ZZZZZZZZZZZ";char ch2[] = "YYYYYYYYY";void * ret2=my_memcpy(ch1, ch2, 6);printf("%s\n", (char *)ret2);return 0;
}

方法二

#include <stdio.h>
#include <assert.h>void* my_memcpy(void* ch1, const void* ch2, size_t num)
{assert(ch1 && ch2);void* ret = ch1;while (num--){*(char*)ch1 = *(char*)ch2;ch1 = (char*)ch1 + 1;ch2 = (char*)ch2 + 1;}return ret;
}int main()
{int arr1[10] = { 0 };int arr2[] = { 1,2,3,4,5,6,7,8 };
void * ret1=my_memcpy(arr1, arr2, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", *(((int*)ret1)++));}printf("\n");char ch1[] = "ZZZZZZZZZZZ";char ch2[] = "YYYYYYYYY";void * ret2=my_memcpy(ch1, ch2, 6);printf("%s\n", (char *)ret2);return 0;
}

memcpy函数针对的对象是内存空间,所以对整形和字符都可以处理

三、memmove函数

1、memmove函数的优势

memcpy函数在使用时会存在问题,比如目标空间和起始空间发生了重叠,此时使用memcpy函数就会出现问题。
看下面的例子
在这里插入图片描述

#include <stdio.h>
#include <assert.h>void* my_memcpy(void* ch1, const void* ch2, size_t num)
{assert(ch1 && ch2);void* ret = ch1;while (num--){*(char*)ch1 = *(char*)ch2;ch1 = (char*)ch1 + 1;ch2 = (char*)ch2 + 1;}return ret;
}int main()
{int arr[10] = { 1,2,3,4,5,6,7 };my_memcpy(arr + 2, arr, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr[i]);}return 0;
}

按照设想,答案应该是 1 2 1 2 3 4 5 0 0 0
但是实际答案是
在这里插入图片描述
是不是没想到?
在这里插入图片描述

这是为什么呢?
主要是在实现的时候,读取到第三个数的时候,本来是3,但是被赋值之后就变成了1,所以第三个数也就成了1,而不是三,后面也是一样。

但是memmove函数可以解决这个问题
在这里插入图片描述

2、memmove函数的模拟实现

像上面实现memcpy一样从前面向后面拷贝出现了问题,那么如果从后面往前面拷贝,又当如何?
在这里插入图片描述

这是就会先将5放到arr[6]上,4放到arr[5]上,依次类推,可以发现,不会出现问题。

但是又有新的问题,如果是memmove(arr,arr+2,20),这又会怎么办呢?

这是从后往前就不行了,就得从前往后拷贝。

聪明的小伙伴,看到这里肯定能够想出解决方案。

  • 当目的地址比起始地址大时,从后往前拷贝
  • 当目的地址比起始地址小时,从前往后拷贝

上代码
在这里插入图片描述

#include <stdio.h>
#include <assert.h>
void* my_memmove(void* ch1, const void* ch2, size_t num)
{assert(ch1 && ch2);void* ret = ch1;if (ch1 > ch2){while (num--)//自减操作后num已经是19了{*((char*)ch1 + num) = *((char*)ch2 + num);//每次自减操作后,num都会少1,向前走了一个字节}}else{while (num--){*(char*)ch1 = *(char*)ch2;ch1 = (char*)ch1 + 1;ch2 = (char*)ch2 + 1;}}return ret;
}int main()
{int arr1[10] = { 0 };int arr2[10] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr2, arr2+2, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

四、memset函数

这个函数比较简单,就不详细讲解了
在这里插入图片描述

1、memset函数的功能

set的意思是设置,我们在这里把它理解成赋值,就是给内存去赋值

先写段代码看看功能吧

#include <stdio.h>int main()
{char ch[20] = "hello world!";memset(ch, 'x', 10);printf("%s\n", ch);return 0;
}

在这里插入图片描述
需要注意的是

memset函数的结构比较特殊
void * memset(void* ptr,int value,size_t num);
第二个参数是int类型,为啥我的例子里面给的是char呢?

是因为char是使用ASCII码值进行操作的。

2、memset函数的模拟实现

比较简单,直接上代码

#include <stdio.h>
#include <assert.h>
void* my_memset(void* ch, int value ,size_t num)
{assert(ch);void* ret = ch;while (num--){*(char*)ch = value;ch = (char*)ch + 1;}return ret;}
int main()
{char ch[20] = "hello world!";my_memset(ch, 'x', 10);printf("%s\n", ch);return 0;
}

在这里插入图片描述
运行成功,yeah

五、memcmp函数

这个函数也比较简单,就是对内存进行比较

1、memcmp函数的基本结构

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

  • 返回值是int 跟strcmp一样
  • 两个指针参数都加上了const ,无法修改内容
  • num是比较的字节数

2、memcmp函数的模拟实现

比较简单,直接上代码
在这里插入图片描述

#include <stdio.h>
#include <assert.h>
int my_memcmp(const void* ptr1, const void* ptr2, size_t num)
{assert(ptr1 && ptr2);while (num--){if (*(char*)ptr1 == *(char*)ptr2){ptr1 = (char*)ptr1 + 1;ptr2 = (char*)ptr2 + 1;}elsereturn *(char*)ptr1 - *(char*)ptr2;}return 0;
}
int main()
{char ch1[20] = { 0 };char ch2[20] = { 0 };gets(ch1);gets(ch2);int num = 0;scanf("%d", &num);int ret = my_memcmp(ch1, ch2, 5);if (ret > 0)printf(">\n");else if (ret < 0)printf("<\n");elseprintf("==\n");return 0;
}


ok ,这次的分享到这里就结束了,函数的内容基本上就要告一段落了

今天下午还会有一更哦,敬请关注!!!


!!!!!!!!!!!!!!!!!求关注!!!!!!!!!!!!!!!!

!!!!!!!!!!!!!!!蹲个一键三连!!!!!!!!!!!!!!!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/95190.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

互联网Java工程师面试题·Dubbo篇·第一弹

目录 1、为什么要用 Dubbo&#xff1f; 2、Dubbo 的整体架构设计有哪些分层? 3、默认使用的是什么通信框架&#xff0c;还有别的选择吗? 4、服务调用是阻塞的吗&#xff1f; 5、一般使用什么注册中心&#xff1f;还有别的选择吗&#xff1f; 6、默认使用什么序列化框架&…

学习记忆——宫殿篇——记忆宫殿——记忆桩——卧室——莫兰勋爵在地铁走失的案子

《神探夏洛克》第三季第一集中提到“思维殿堂”&#xff0c;其实指的就是记忆宫殿。讲述了一个名叫莫兰勋爵在地铁走失的案子&#xff0c;这里简单给大家罗列以下破案信息&#xff1a; 订阅报纸的男人、伦敦养狗的女人、穿着黑色运动的非裔女人、松木、云杉、雪松、新樟脑球、碳…

AtCoder Beginner Contest 232(A-G)

A - QQ solver (atcoder.jp)直接按题意模拟即可。 B - Caesar Cipher (atcoder.jp)按题意模拟即可 C - Graph Isomorphism (atcoder.jp)按题意模拟即可 D - Weak Takahashi (atcoder.jp) 一个非常套路的网格dp E - Rook Path (atcoder.jp) &#xff08;1&#xff09;题意 有…

探秘前后端开发世界:猫头虎带你穿梭编程的繁忙街区,解锁全栈之路

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

【Java】接口 interface

目录 概述 示例代码&#xff1a; 接口成员访问特点 示例代码&#xff1a; 概述 什么是接口 接口就是一种公共的规范标准&#xff0c;只要符合规范标准&#xff0c;大家都可以调用。 Java 中的接口更多的体现在对行为的抽象&#xff01; 1. 接口 用关键字 interface 修饰 pub…

从零手搓一个【消息队列】创建核心类, 数据库设计与实现

文章目录 一、创建核心类1, 交换机2, 交换机类型3, 队列4, 绑定5, 交换机转发 & 绑定规则6, 消息7, 消息属性 二、数据库设计1, 使用 SQLite2, 使用 MyBatis2.1, 创建 Interface2.2, 创建 xml 文件 三、硬盘管理 -- 数据库1, 创建 DataBaseManager 类2, init() 初始化数据库…

算法题系列10·最长公共前缀

目录 题目描述 思路 实现 题目描述 编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀&#xff0c;返回空字符串 ""。示例 1&#xff1a; 输入&#xff1a;strs ["flower","flow","flight"] 输出&#xff1a;&qu…

LabVIEW开发教学实验室自动化INL和DNL测试系统

LabVIEW开发教学实验室自动化INL和DNL测试系统 如今&#xff0c;几乎所有的测量仪器都是基于微处理器的设备。模拟输入量在进行数字处理之前被转换为数字量。对于参加电气和电子测量课程的学生来说&#xff0c;了解ADC以及如何欣赏其性能至关重要。ADC的不确定性可以根据其传输…

蓝桥杯每日一题2023.10.5

3420. 括号序列 - AcWing题库 题目描述 题目分析 对于这一我们需要有前缀知识完全背包 完全背包的朴素写法&#xff1a; #include<bits/stdc.h> using namespace std; const int N 1010; int n, m, v[N], w[N], f[N][N]; int main() {cin >> n >> m;fo…

PyTorch实例:简单线性回归的训练和反向传播解析

文章目录 &#x1f966;引言&#x1f966;什么是反向传播&#xff1f;&#x1f966;反向传播的实现&#xff08;代码&#xff09;&#x1f966;反向传播在深度学习中的应用&#x1f966;链式求导法则&#x1f966;总结 &#x1f966;引言 在神经网络中&#xff0c;反向传播算法…

华为OD七日集训第6期 十一特辑 - 按算法分类,由易到难,循序渐进,玩转OD

目录 专栏导读华为OD机试算法题太多了&#xff0c;知识点繁杂&#xff0c;如何刷题更有效率呢&#xff1f; 一、逻辑分析二、数据结构1、线性表① 数组② 双指针 2、map与list3、优先队列4、滑动窗口5、二叉树6、并查集7、栈 三、算法1、基础算法① 贪心算法② 二分查找③ 分治…

OpenCV 15(SIFT/SURF算法)

一、SIFT Harris和Shi-Tomasi角点检测算法&#xff0c;这两种算法具有旋转不变性&#xff0c;但不具有尺度不变性&#xff0c;以下图为例&#xff0c;在左侧小图中可以检测到角点&#xff0c;但是图像被放大后&#xff0c;在使用同样的窗口&#xff0c;就检测不到角点了。 尺度…

JavaScript操作CSS样式

上节课我们基本完成了游戏的主体&#xff0c;这节课我们来学习如果使用JavaScript去操作CSS样式 ● 例如&#xff0c;我们现在想当玩家输入对的数字之后&#xff0c;我们讲背景改为绿色&#xff0c;并且把number的框宽度变大 const secretnumber Math.trunc(Math.random() * …

经典算法-----汉诺塔问题

前言 今天我们学习一个老经典的问题-----汉诺塔问题&#xff0c;可能在学习编程之前我们就听说过这个问题&#xff0c;那这里我们如何去通过编程的方式去解决这么一个问题呢&#xff1f;下面接着看。 汉诺塔问题 问题描述 这里是引用汉诺塔问题源自印度一个古老的传说&#x…

目前制造企业生产计划现状是什么?有没有自动化排产系统?

大家都知道&#xff0c;人的指挥中心是大脑&#xff0c;大脑对我们的发出各种各样的指令&#xff0c;告诉我们&#xff1a;“手”做什么事情&#xff0c;“眼睛”看什么地方&#xff0c;“耳朵”听什么声音&#xff0c;然后再将摸到的、看到的、听到的信息传递给大脑&#xff0…

制作 3 档可调灯程序编写

PWM 0~255 可以将数据映射到0 75 150 225 尽可能均匀电压间隔

maven下载、本地仓库设置与idea内置maven设置

一、下载安装maven maven下载官网&#xff1a;https://maven.apache.org/download.cgi 下载到本地后解压 二、配置环境变量 我的电脑-属性-高级系统设置-环境变量/系统变量 新建MAVEN_HOME 变量值为自己的maven包所在的位置 编辑path 添加 %MAVEN_HOME%\bin 三、测试 Win…

一个案例熟悉使用pytorch

文章目录 1. 完整模型的训练套路1.2 导入必要的包1.3 准备数据集1.3.1 使用公开数据集&#xff1a;1.3.2 获取训练集、测试集长度&#xff1a;1.3.3 利用 DataLoader来加载数据集 1.4 搭建神经网络1.4.1 测试搭建的模型1.4.2 创建用于训练的模型 1.5 定义损失函数和优化器1.6 使…

redis持久化与调优

一 、Redis 高可用&#xff1a; 在web服务器中&#xff0c;高可用是指服务器可以正常访问的时间&#xff0c;衡量的标准是在多长时间内可以提供正常服务&#xff08;99.9%、99.99%、99.999%等等&#xff09;。但是在Redis语境中&#xff0c;高可用的含义似乎要宽泛一些&#x…

POJ 2886 Who Gets the Most Candies? 树状数组+二分

一、题目大意 我们有N个孩子&#xff0c;每个人带着一张卡片&#xff0c;一起顺时针围成一个圈来玩游戏&#xff0c;第一回合时&#xff0c;第k个孩子被淘汰&#xff0c;然后他说出他卡片上的数字A&#xff0c;如果A是一个正数&#xff0c;那么下一个回合他左边的第A个孩子被淘…