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

C语言内存操作函数

目录

一. C语言内存操作函数

1. memcpy的使用和模拟实现

2. memmove函数

3. memset函数

4. memcmp函数


一. C语言内存操作函数

随着知识的不断积累,我们所想要实现的目标程序就会更加复杂,今天我们来学习一个新的知识叫做C语言内存操作函数,它是C语言标准库中提供的一系列对内存进行操作的函数。比如对于内存的复制,内存的设置以及内存的比较,这些函数都是针对内存块来处理的,为程序员提供了更加安全,高效和灵活的方式,让程序员能够对内存进行各种常见的操作和处理,下面就让我们来详细了解一下吧。😁🤗🤗

1. memcpy的使用和模拟实现

首先我们来认识memcpy函数,它的原型是void* memcpy(void* destination, const void* soure,size_t num),作用就是内容的复制,从soure的位置开始向后复制num个字节(注意单位是字节)的数据到destination指向的内存位置这个函数遇到'/0'的时候并不会停下来并且destination和soure有任何的重叠,复制的结果都是未定义的。下面给出大家实际的例子:

#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };memcpy(arr2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

 对于运行结果来说我们也可以看出来如果num小于实际输出的数量,那么后面都是用0来补的,大家下去可以自己多尝试进行练习。

🎡🎡如何模拟实现memecpy函数呢?

#include <assert.h>
void* my_memcpy(void* str1, const void* str2, size_t num)
{void* ret = str1;assert(str1);assert(str2);/** copy from lower addresses to higher addresses*/while (num--) {*(char*)str1 = *(char*)str2;str1 = (char*)str1 + 1;str2 = (char*)str2 + 1;}return(ret);
}
int main()
{int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };int arr2[10] = { 0 };my_memcpy(arr2, arr1, 40);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr2[i]);}return 0;
}

在我们模拟实现的过程中,在开始的时候我们要注意两个指针不能是空指针,需要assert进行断言,我们为什么要进行强制类型转换成char*呢?首先我们要明确memcpy函数传入第三个参数size_t num是字节的个数,所以当我们强制类型转换的时候会更加方便去计算,另外就是我们的指针是void*类型的,是不能直接进行加减运算的,最终返回一个void*的指针。

2. memmove函数

接下来认识memmove函数,它的原型是void* memmove(void* destination,const void* scoure,size_t num),原型与memcpy函数是一模一样的,所以说其实memmove函数与memcpy函数的区别就是memmove函数可以处理重叠部分。也就是说如果源空间也目标空间出现重叠的话,我们就使用memmove函数来处理。给大家举一个例子说明:

#include <stdio.h>
#include <string.h>
int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };memmove(arr1 + 2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;
}

 其实对于我们memmove函数的实现其实是更复杂的,那么我们究竟要如何实现它呢?大家看下面面的四种情况:

sour代表的是源空间,des代表的是目标函数,大家认真看第一个,如果我们将sour里面的内容复制到des中,我们可以直接按顺序将34567依次放入12345中,最终我们的打印结果就是3 4 5 6 7 6 7 8 9 10,但是我们来看第三种,如果我们将34567按顺序放在56789中,我们会发现当我们放完3和4之后,原本的5和6就会变成3和4,那么原来应该把5和6放在7和8位置上的计划就不能实现,所以这样放是不对的,但我们换一种方法,我们先将7放入9,再将6放入8,也就是从后面往前面放置,对于第四种来说,从前往后和从后往前都是一样的。所以我给出大家一张图来更好的说明:我们的数组有高低地址之分,也就是说当我们的des小于sour的时候我们选择从前往后,除此之外我们选择从前往后,所以了解了底层的逻辑下面我们就开始设计我们的代码: 

#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memmove(void* dest, const void* sour, size_t num)
{assert(dest && sour);void* ret = dest;if (dest < sour)//从前往后{while (num--){*(char*)dest = *(char*)sour;dest = (char*)dest + 1;sour = (char*)sour + 1;}}else//从后往前{while (num--){*((char*)dest + num) = *((char*)sour + num);}}return ret;};int main()
{int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };my_memmove(arr1 + 2, arr1, 20);int i = 0;for (i = 0; i < 10; i++){printf("%d ", arr1[i]);}return 0;
}

但是可能细心的同学会发现,我们就算使用memcpy函数也能够实现重叠部分的程序运算,但是我们在C语言中更推荐规范使用,如果有重叠部分的就使用memmove函数,虽然我们在VS的编译器上用memcpy来处理重叠部分可以成功,但是在其他编译器上却不一定,所以我们尽量的规范使用。

3. memset函数

🧣🧣memset函数是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。它的原型是void* memset(void* ptr,int value,size_t num);ptr就指向要被填充的内存块指针,value要设置的内容,num就表示要设置成多少个字节。

#include <stdio.h>
#include <string.h>
int main ()
{char str[] = "hello world";memset (str,'x',6);printf(str);return 0;

 

4. memcmp函数

🧀🧀memcmp函数是用来比较两个指针大小的,它的原型是int memcmp(const void* ptr1,const void* ptr2,size_t num),就是对内存块ptr1和ptr2进行比较,比较从ptr1和ptr2指针指向的位置开始,向后的num个字节,注意也是以字节为单位,当ptr1>ptr2的时候,返回大于0的值,当两个相等的时候,返回0,当ptr1<ptr2的时候,返回小于0的值

#include <stdio.h>
#include <string.h>
int main()
{char buffer1[] = "DWgaOtP12df0";char buffer2[] = "DWGAOTP12DF0";int n;n = memcmp(buffer1, buffer2, sizeof(buffer1));if (n > 0) printf("'%s' is greater than '%s'.\n", buffer1, buffer2);else if (n < 0) printf("'%s' is less than '%s'.\n", buffer1, buffer2);elseprintf("'%s' is the same as '%s'.\n", buffer1, buffer2);return 0;

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 力扣第 411 场周赛题解
  • 西安旅游系统--论文pf
  • 每日快讯 | 京东健康:2024年上半年营收283亿元
  • vue+fastadmin跨域请求问题
  • 【Docker】宿主机上装个ES和使用docker装个ES有啥不一样
  • 【gitlab】gitlab-ce:17.3.0-ce.0 之2:配置
  • Windows 上使用 OpenSSL 生成一个 10 年有效期的自签名 PFX 证书
  • Spring Boot 3.3 【五】Spring Boot 整合JPA-原生SQL支持
  • 萝卜快跑和端到端的自动驾驶(1)
  • mysql 之 explain
  • c语言基础-------数组元素的指针
  • 2024新型数字政府综合解决方案(七)
  • Apache Doris 中Compaction问题分析和典型案例
  • drawio的问题
  • 24 初入python
  • [PHP内核探索]PHP中的哈希表
  • [ 一起学React系列 -- 8 ] React中的文件上传
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 2017-08-04 前端日报
  • extjs4学习之配置
  • Javascript基础之Array数组API
  • Js基础知识(四) - js运行原理与机制
  • KMP算法及优化
  • Mocha测试初探
  • mysql 5.6 原生Online DDL解析
  • MySQL的数据类型
  • MySQL用户中的%到底包不包括localhost?
  • React Transition Group -- Transition 组件
  • Stream流与Lambda表达式(三) 静态工厂类Collectors
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • vue2.0一起在懵逼的海洋里越陷越深(四)
  • 百度地图API标注+时间轴组件
  • 从零开始的无人驾驶 1
  • 第三十一到第三十三天:我是精明的小卖家(一)
  • 利用jquery编写加法运算验证码
  • 前端学习笔记之观察者模式
  • 如何抓住下一波零售风口?看RPA玩转零售自动化
  • 《天龙八部3D》Unity技术方案揭秘
  • # 学号 2017-2018-20172309 《程序设计与数据结构》实验三报告
  • #【QT 5 调试软件后,发布相关:软件生成exe文件 + 文件打包】
  • #php的pecl工具#
  • #多叉树深度遍历_结合深度学习的视频编码方法--帧内预测
  • (55)MOS管专题--->(10)MOS管的封装
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (补充)IDEA项目结构
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (力扣题库)跳跃游戏II(c++)
  • (四)库存超卖案例实战——优化redis分布式锁
  • (四)事件系统
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (转)IOS中获取各种文件的目录路径的方法
  • .equals()到底是什么意思?
  • .NET Core 中的路径问题