当前位置: 首页 > news >正文

【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语言进阶】内存函数

天生我材必有用&#xff0c;千金散尽还复来。 ——李白 目录 前言 一.memcpy函数 ​1.实现memcpy函数 2.模拟实现memcpy函数 二.memmove函数 1.实现memmove函数 2.模拟实现memmove函数 三.memcpy函数和memmove函数的关系 四.memcm…...

Java开发 - ELK初体验

前言 前面我们讲过消息队列&#xff0c;曾提到消息队列也具有保存消息日志的能力&#xff0c;今天要说的EL看也具备这个能力&#xff0c;不过还是要区分一下功能的。消息队列的日志主要指的是Redis的AOF&#xff0c;实际上只是可以利用了消息队列来保存&#xff0c;却并不是消…...

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 标题&#xff1a;UPRISE&#xff1a;改进零样本评估…...

JS运行环境、包管理、打包工具总结

&#x1f333;JS运行环境-node.js 运行环境就是代码解析和执行的程序&#xff0c;比如jvm等虚拟机&#xff0c;他们的主要工作就是根据设定的语法规则解析编译代码&#xff0c;然后运行代码。 js的语法规则遵循ES规范。 &#x1f341;node.js Node.Js官网 Node.js是一种基于Ch…...

day4网络编程(广播和组播)

1.广播 发送端&#xff08;类似于客户端&#xff09; 流程&#xff1a; 创建套接字 填充接收端&#xff08;服务器&#xff09;网络信息结构体 bind(非必须绑定) 设置允许广播 向接收端&#xff08;服务器&#xff09;发送数据 关闭套接字文件 #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.数据信息可视化四、相关附件前言 在现代信息化时代&#xff0c;图形化用户界面&#xff08;Graphical User Interface, GUI&#xff09;已经成为各种软件应用和…...

蓝桥杯嵌入式第一课--创建工程

概述学习本节之前&#xff0c;必须要先安装好 keil5 以及 CubeMX 等软硬件环境&#xff0c;如果你已经安装完成&#xff0c;请告诉自己&#xff1a;考试现在开始&#xff01;从CubeMX开始CubeMX是创建工程模板的软件&#xff0c;也是我们比赛时第一个要进行操作的软件。一、选择…...

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在当前文件进行文本查找 &#xff08;必备&#xff09;Ctrl R在当前文件进行文本替换 &#xff08;必备&#xff09;Ctrl Z撤销 &#xff08;必备&#xff09;Ctrl Y删除光标所在行 或 删除选中的行 &#xff08;必备&#xff09;Ctrl X剪切光标所在行…...

宝塔控制面板常用Linux命令大全

宝塔面板是站长朋友们常见的一款服务器运维面板&#xff0c;可以通过 Web 端轻松管理服务器&#xff0c;提升运维效率。大家在服务器中安装宝塔面板会用到宝塔面板特定的脚本命令。今天这篇文章为大家整理汇总了宝塔面板常用Linux命令&#xff0c;这样方便大家收藏查找。 1、安…...

C语言实现单链表(超多配图,这下不得不学会单链表了)

目录 一&#xff1a;什么是链表&#xff1f; 二&#xff1a;创建源文件和头文件 (1)头文件 (2)源文件 三&#xff1a;实参和形参 四&#xff1a;一步步实现单向链表 &#xff08;1&#xff09;建立一个头指针并置空 &#xff08;2&#xff09;打印链表&#xff0c;便于…...

SQL编写优化技巧

一、底层原理 sql慢是因为没有走索引&#xff0c;因此需要添加索引然它走索引联合索引需要匹配最左匹配原则&#xff08;索引回表&#xff09;如果查询列超出索引的key&#xff0c; 会导致回表&#xff0c;回表数量多&#xff0c;则会走全表扫描 索引是分聚集索引、非聚集索引…...

【基础算法】单链表的OJ练习(6) # 复制带随机指针的链表 #

文章目录&#x1f347;前言&#x1f34e;复制带随机指针的链表&#x1f351;写在最后&#x1f347;前言 本章的链表OJ练习&#xff0c;是最后的也是最难的。对于本题&#xff0c;我们不仅要学会解题的思路&#xff0c;还要能够通过这个思路正确的写出代码&#xff0c;也就是思路…...

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语言期末真题实战

很简单的一道程序阅读题&#xff0c;pa’默认为a【0】&#xff0c;接下来会进行3次循环 0 1 2 输出结果即可 前3题就是一些基础定义&#xff0c;在此不多赘述 要注意不同的数据类型的字节数不同 a<<2 b>>1&#xff08;b>>1;就是说b自身右位移一位&#xff08…...

【Shell】Shell变量

Shell变量系统预定义变量自定义变量基本语法定义变量撤销变量命名规则使用变量只读变量删除变量变量类型系统预定义变量 $HOME、$PWD、$SHELL、$SUSER等 实例 yysubuntu:~$ echo $HOME #查看系统变量的值 /home/yys yysubuntu:~$ set #显示当前shell中所有变量自定义变量…...

你是真的“C”——结构体中鲜有人知的“秘密”

你是真的“C”——结构体中的精髓剖析【内存对齐】 【位段】 &#x1f60e;前言&#x1f64c;结构体内存对齐&#xff1a;&#x1f60a;结构体内存对齐存在的意思是什么&#xff1f;&#x1f618;内存对齐例子详细剖析&#xff1a;&#x1f618;结构体中的位段&#xff1a;&…...

2023年“网络安全”赛项江苏省淮安市赛题解析(超详细)

2023年中职组江苏省淮安市“网络空间安全”赛项 ①.2023年中职组江苏省淮安市任务书②.2023年中职组江苏省淮安市解析③.需要环境或者不懂的可以私信博主!①.2023年中职组江苏省淮安市任务书 任务一:服务器内部信息获取 任务环境说明: 服务器场景:Server210510(关闭链接…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院查看报告小程序

一、开发环境准备 ​​工具安装​​&#xff1a; 下载安装DevEco Studio 4.0&#xff08;支持HarmonyOS 5&#xff09;配置HarmonyOS SDK 5.0确保Node.js版本≥14 ​​项目初始化​​&#xff1a; ohpm init harmony/hospital-report-app 二、核心功能模块实现 1. 报告列表…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 &#x1f4dd; 在上一篇文章中&#xff0c;我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源&#xff0c;方便后续将资源打包到一个可执行文件中。 2.embed介绍 &#x1f3af; Go 1.16 引入了革命性的 embed 包&#xff0c;彻底改变了静态资源管理的…...

laravel8+vue3.0+element-plus搭建方法

创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题

【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要&#xff1a; 近期&#xff0c;在使用较新版本的OpenSSH客户端连接老旧SSH服务器时&#xff0c;会遇到 "no matching key exchange method found"​, "n…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...