【内存函数】-关于内存的操作函数

news2024/9/27 13:15:51

作者:小树苗渴望变成参天大树
作者宣言:认真写好每一篇博客
作者gitee:gitee
在这里插入图片描述
如 果 你 喜 欢 作 者 的 文 章 ,就 给 作 者 点 点 关 注 吧!

内存函数

  • 前言
  • 一、[memcpy](https://cplusplus.com/reference/cstring/memcpy/?kw=memcpy)
  • 二、[memmove](https://cplusplus.com/reference/cstring/memmove/)
  • 三、[memcmp](https://cplusplus.com/reference/cstring/memcmp/)
  • 四、[memset](https://legacy.cplusplus.com/reference/cstring/memset/?kw=memset)
  • 五、总结


前言

各位友友们,我们又见面了,前段时间讲了字符和字符串函数,今天我们来讲讲内存操作函数,我们在是实现两个数组之间的拷贝,比较的时候,就没有办法使用这些字符串函数了,所以我们今天就讲一下内存函数,这些函数可以实现数组之间的操作,那让我们进入正文吧!


一、memcpy

void * memcpy ( void * destination, const void * source, size_t num );//src里面的内容不会被修改,所以用const修饰

1.函数memcpy从source的位置开始向后复制num个字节的数据到destination的内存位置。
2.这个函数在遇到 ‘\0’ 的时候并不会停下来。
3.如果source和destination有任何的重叠,复制的结果都是未定义的。

例子:

#include<stdio.h>
int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 6,7,8,9,10 };
	memcpy(arr1, arr2, 12);//把arr2前3个元素拷贝到arr1前三个元素中去
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

运行结果:
在这里插入图片描述

模拟实现:

void * memcpy ( void * dst, const void * src, size_t count)
{
        void * ret = dst;
 assert(dst);
   assert(src);
     while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
       }
        return(ret);
}

分析代码:
在这里插入图片描述
我们来思考,用自己实现的memcpy函数自己给自己拷贝会出现什么情况??

我们来看看一下结果:
在这里插入图片描述

原因是你从前往后面拷贝,会覆盖掉后面要被拷过去的内容,所以出现问题,这时候memcpy就不行了,这时候就有了下面的函数

二、memmove

void * memmove ( void * destination, const void * source, size_t num );//src里面的内容不会被修改,所以用const修饰

和memcpy的差别就是memmove函数处理的源内存块和目标内存块是可以重叠的。
如果源空间和目标空间出现重叠,就得使用memmove函数处理。

例子:

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 6,7,8,9,10 };
	memmove(arr1+2, arr1, 12);
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

在这里插入图片描述

模拟实现:

void * memmove ( void * dst, const void * src, size_t count)
{
        void * ret = dst;
        if (dst <= src || (char *)dst >= ((char *)src + count)) {
           while (count--) {
                        *(char *)dst = *(char *)src;
                        dst = (char *)dst + 1;
                        src = (char *)src + 1;
               }
       }
        else {
                dst = (char *)dst + count - 1;
                src = (char *)src + count - 1;
                while (count--) {
                        *(char *)dst = *(char *)src;
                        dst = (char *)dst - 1;
                        src = (char *)src - 1;
               }
       }
        return(ret);
}

分析:
在这里插入图片描述

大家可以下来自己测试一下我自主实现的memmove函数是否能解决刚才的问题。
但是实际的库里面的memcpy也可以实现重叠拷贝的问题了,只是我们自己实现的没有达到这个功能,那我们为什么有了memmove,还要有memcpy呢??我们只能大胆猜测,先有的memcpy,在有的memmove,后来对memcpy进行了完善了,才达到了现在和memmove几乎相同的功能

三、memcmp

接下来我们来介绍一下memcmp

int memcmp ( const void * ptr1, const void * ptr2, size_t num );//两个里面的内容不会被修改,所以都用const修饰一下

比较从ptr1和ptr2指针开始的num个字节
返回值如下:
在这里插入图片描述

例子:

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 1,2,4,5 };
	int ret=memcmp(arr1, arr2, 12);
	printf("%d", ret);
	return 0;
}

运行结果:
在这里插入图片描述
和strcmp一样的道理,开始比到第一个不相等的数,谁大就返回大于0的数,则反之,后面的数不在比较了。

模拟实现:

int my_memcmp(const void* str1, const void* str2, size_t num)
{
	assert(str1 && str2);
	while (num--)
	{
		if (*(char*)str1 > *(char*)str2)
		{
			return 1;
		}
		if (*(char*)str1 < *(char*)str2)
		{
			return -1;
		}
		str1 = (char*)str1 + 1;
		str2 = (char*)str2 + 1;
	}
	return 0;
}

因为事先不知道使用者会传什么类型的数组进来,所以在模拟实现的实现选择一个字节的比较,要强制转换成char*类型,一次访问一个字节

四、memset

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

第一个参数,要设置的内存地址
第二个参数,要设置的值,值作为int传递,传整型家族的就行
第三个参数,要设置为值的字节数。

例子:

int main()
{
	char arr[] = "hello world";
	memset(arr, 'x', 5);
	printf("%s\n", arr);
	memset(arr+6, 'y', 5);
	printf("%s\n", arr);
	int arr1[10] = { 1 };
	memset(arr1,1, 40);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

在这里插入图片描述

我们可以看到第三个我们本来是想打印全部为1,结果却是一个很大的数,原因是,设置是一个字节进行设置的,这样写就比较,把每个字节都设置成1,我们知道一个整型有四个字节,1其中只有一个字节是1,其余的为0;我们只要把控这个就可以很好的使用memset函数了,

模拟实现:

void* my_memset(void* ptr, int value, size_t num)
{
	assert(ptr);
	while (num--)
	{
		*(char*)ptr = value;
		(char*)ptr = (char*)ptr + 1;
	}
}

我们可以参考上面的代码,去理解分析这个代码为什么要这么写

五、总结

我们今天介绍了内存操作函数,我们需要知道他们的使用场景,和字符串函数要分清楚了,千万不要记混了,是在想不起来的时候我们可以查看文档,这些函数我们不需要深度了解他的模拟实现,博主在这里模拟实现,主要是让大家能更好的理解,我们只需要会使用库里面的这些函数就行了,大家下去自己去好好理解这些函数,我们今天就讲到这里,我们下篇再见

在这里插入图片描述

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

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

相关文章

初识软件测试

作者&#xff1a;~小明学编程 文章专栏&#xff1a;测试开发 格言&#xff1a;热爱编程的&#xff0c;终将被编程所厚爱。 目录 什么是软件测试&#xff1f; 软件测试和软件开发的区别&#xff1f; 调试和测试的区别&#xff1f; 优秀的测试人员应该具备哪些素质&#xff…

cherry-pick的定义和使用方法

1、定义 使用遴选&#xff08;cherry-pick&#xff09;命令&#xff0c;Git 可以让你将任何分支中的个别提交合并到你当前的 Git HEAD 分支中。当执行 git merge 或者 git rebase 时&#xff0c;一个分支的所有提交都会被合并。cherry-pick 命令允许你选择单个提交进行整合。 …

正点原子STM32(基于HAL库)3

目录RTC 实时时钟实验RTC 时钟简介RTC 框图RTC 寄存器硬件设计低功耗实验电源控制&#xff08;PWR&#xff09;简介电源系统电源监控电源管理PVD 电压监控实验PWR 寄存器硬件设计睡眠模式实验硬件设计停止模式实验PWR 寄存器硬件设计待机模式实验PWR 寄存器硬件设计ADC 实验ADC…

全国产加固以太网交换机选择技巧

全国产加固交换机用于连接以太网设备&#xff1a;首先接收由某台设备发出的数据帧&#xff0c;然后再将这些帧传送到与其它以太网设备相连的适当交换机端口上。随着它传送这些帧&#xff0c;学习并掌握以太网设备的位置&#xff0c;并用这些信息来决定该用哪些端口来传送帧&…

83. 深度循环神经网络及代码实现

1. 回顾&#xff1a;循环神经网络 2. 更深 再看公式&#xff1a; 3. 总结 深度循环神经网络使用多个隐藏层来获得更多的非线性性 4. 代码简洁实现 实现多层循环神经网络所需的许多逻辑细节在高级API中都是现成的。 简单起见&#xff0c;我们仅示范使用此类内置函数的实现方式…

虚拟机本地搭建Hadoop集群教程

Hadoop概述 狭义下Hadoop是Apache的一套开源软件&#xff0c;用java实现&#xff0c;广义上是围绕Hadoop打造的大数据生态圈 http://hadoop.apache.org Hadoop核心组件&#xff1a; HDFS&#xff08;分布式文件存储系统&#xff09;&#xff1a;解决海量数据存储YARN&#…

Spring 常用组件

一. Spring 解决了什么问题 Spring 核心功能是整合&#xff0c;提供一个管理组件的容器&#xff0c; 以 Bean的形式管理组件及对象。Spring 采用分层架构和组件化设计&#xff0c;允许分层&#xff0c;插件化选择组件。二. Spring 整体架构 Spring4架构图 三. Spring 组件 1.…

Spring | 整合MyBatis中SqlSessionTemplate和MapperScannerConfigurer类的使用

0️⃣初始配置&#x1f6a9;pom.xml导入依赖<?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"ht…

大数据开发工程师考试分享

在2022年年尾伴随着疫情政策的放开&#xff0c;压抑了3年的活力与生机正在悄然地蓄势待发。回顾这一整年&#xff0c;我们经历了核酸考验&#xff0c;互联网裁员危机&#xff0c;以及正面面对新冠等等。总之&#xff0c;在这一年无论是生活还是工作&#xff0c;大家都面临了不同…

大公司VS小公司,怎样选择更有前途?

你好&#xff0c;我是王喆。 学完上一讲&#xff0c;你已经知道了如何选择一个有前景的职业方向。在大方向确定好之后&#xff0c;接下来的问题就是如何在这个方向上进行具体的职业发展规划了。 我想你一定听说过很多牛人的“职场升级”故事&#xff1a;工作3年升到P7&#x…

春节不打烊,这份安全应急指南请收好!

春节作为中国的传统节日&#xff0c;不仅是各个企业的营销重点周期&#xff0c;也是黑灰产高发节点之一。尤其是伴随着互联网的兴起&#xff0c;春节红包逐渐成为主流营销节目&#xff0c;从支付宝的集五福到各种各样的红包活动&#xff0c;不断翻新的营销花样让黑灰产们赚的盆…

JUC面试(三)——CAS

CAS CAS的全称是Compare-And-Swap&#xff0c;它是CPU并发原语&#xff0c;自旋锁 它的功能是判断内存某个位置的值是否为期望值&#xff0c;如果是则更改为新的值&#xff0c;这个过程是原子的 CAS并发原语体现在Java语言中就是sun.misc.Unsafe类的各个方法。调用UnSafe类中…

深度学习 GAN生成对抗网络-1010格式数据生成简单案例

一、前言 本文不花费大量的篇幅来推导数学公式&#xff0c;而是使用一个非常简单的案例来帮助我们了解GAN生成对抗网络。 二、GAN概念 生成对抗网络&#xff08;Generative Adversarial Networks&#xff0c;GAN&#xff09;包含生成器&#xff08;Generator&#xff09;和鉴…

HyperLogLog和Set比较 !!!

HyperLogLog和Set比较 HyperLogLog HyperLogLog常用于大数据量的统计&#xff0c; 比如页面访问量统计或者用户访问量统计&#xff0c;作为一种概率数据结构&#xff0c;HyperLogLog 以完美的精度换取高效的空间利用率。Redis HyperLogLog 实现最多使用 12 KB&#xff0c;并提…

docker推送镜像至阿里私有镜像仓库

文章目录一、注册阿里私有镜像仓库二、将公共镜像推送至私有镜像仓库1、首先拉取到mysql镜像2、登录阿里云Docker Registry&#xff08;这里的信息要更换成自己的&#xff09;3、将mysql镜像推送至Registry4、查看5、拉取镜像三、将正在启动的容器导出并推送至私有仓库1、将启动…

二分查找的最多比较次数

答案 对于二分搜索次数最多的问题&#xff0c;计算公式为&#xff0c;其中a , b , n 均为整数 当顺序表有n个关键字时候&#xff0c;查找失败&#xff0c;至少需要比较a次关键字 查找成功&#xff0c;至少需要b次 举例 已有从小到大排序的10000个数据&#xff0c;用二分查…

密码框限制xxs注入字符处理

<template><a-form-model-item ref"password" prop"password"><a-input-passwordplaceholder"请输入登录密码"v-model"cusForm.password"/></a-form-model-item> </template><script> export def…

「自控原理」3.2 二阶系统时域分析

本节介绍二阶系统的时域分析&#xff0c;主要介绍欠阻尼情况下的时间响应与动态性能指标 文章目录概述极点的表示方法无阻尼响应临界阻尼响应过阻尼响应欠阻尼响应欠阻尼系统的单位阶跃响应动态性能与极点分布的关系例题改善二阶系统动态性能的措施概述 二阶系统时间响应比较重…

elementUI如何设置input不可编辑

打开一个vue文件&#xff0c;添加一个input标签。如图&#xff1a; 添加disabled设置不可编辑。如图&#xff1a; 保存vue文件后使用浏览器打开&#xff0c;页面上显示的input已经实现不可编辑效果。如图&#xff1a; 参考&#xff1a;elementUI如何设置input不可编辑-百度…

出现死锁的场景分析及解决方法

在上一篇互斥锁的时候最后使用Account.class作为互斥锁&#xff0c;来解决转载问题&#xff0c;所有的账户转账操作都是串行的&#xff0c;性能太差。 我们可以考虑缩小锁定的范围&#xff0c;使用细粒度的锁&#xff0c;来提高并行度。例如用两把锁&#xff0c;转出账本一把&…