内存函数(C语言)

news2024/9/21 14:42:27

内存函数

以下函数的头文件:string.h

  • 针对内存块进行处理的函数

memcpy

函数原型:

void* memcpy(void* destination, const void* source, size_t num);
					目标空间地址                源空间地址
  • num,被拷贝的字节个数

  • 返回目标空间的起始地址

  • 从source函数向后拷贝num字节个数据到目标空间

  • 目标空间地址和源空间地址有重叠部分,有重叠内存的拷贝,结果是未定义的

  • C语言标准规定:memcpy可以不负责有重叠内存的拷贝

    • 而vs编译器的库函数也可以实现重叠内存的拷贝。
#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[20] = { 1, 2, 3, 4, 5, 6 };
	int arr2[20] = { 0 };
	memcpy(arr2, arr1, sizeof(int) * 5);
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

在这里插入图片描述

通过函数原型也发现,这个memcpy函数是一个函数参数,函数返回类型都是void无符号类型,这是说明该函数是一个,泛型函数,它可以接收任意类型的参数,使同一个函数能用于多种类型的数据

该用例说明了,将数组arr1从第一个元素开始的20个字节拷贝到arr2中。

模拟memcpy函数

void* my_memcpy(void* dest, const void* src, size_t num)
{
    void* ret = dest;
    assert(dest && src);
    while(num--)
    {
        *(char*)dest = *(char*)src;
        dest = (char*)dest + 1;
        src = (char*)src + 1;
    }
	return ret;
}

该函数是泛型函数,在返回类型和参数上要保持一致,后面的size_t num参数用来接收拷贝的字节个数。

能够进行任意数据类型的拷贝,这里只能将源空间一个一个字节拷贝到目标空间里,而void类型不是4个字节,所以将,dest和src强制类型转换为char类型,这样每循环一次就拷贝一个字节的内容,然后让指针dest和src向后走一个字节。

(char*)dest++;dest = *(char*)dest + 1;的区别:

c/c++里的强制类型转换,是临时的,(char*)dest++;试图将一个 void *类型的dest强制类型转换,然后++,语法是有问题的,对 (char *)dest使用++,实际上是 (char* dest) = dest + 1;,将无符号类型的指针赋给 char *类型的指针编译器会报错的
在这里插入图片描述

最后将目标空间的起始地址返回即可。

使用assert断言是因为,目标空间和源空间都不能为空,否则就是对空指针解引用,加一条assert是代码具有更好的健壮性。

memmove

函数原型:

void* memmove(void* destination, const void* source, size_t num);
  • 负责重叠内存的拷贝
  • 用法与memcpy相同。
  • memmove可以是memcpy的替代,它支持更多的使用场景,重叠内存的拷贝。

模拟memmove函数

俩个函数的功能及其相似,它们在实现上的不同,模拟memcpy函数是,对字节进行拷贝时,是将source里的字节从前向后一个一个拷贝的,如图:

source里一共有12个字节,模拟的memcpy函数将从数字2开始的第一个字节,一个一个拷贝到目标空间里。
在这里插入图片描述

在这里插入图片描述

若两快空间重叠时会发生哪些情况:

  • dest指针大于source指针,目标空间与源空间重叠,但目标空间起始地址小于源空间,此时针对情况一,如上图橘色与蓝色重叠部分
  • dest指针小于source指针,目标空间与源空间重叠,但目标空间起始地址大于源空间,此时针对情况二,如上图绿色与蓝色重叠部分

情况一:

  • 当使用从前向后一个一个字节的拷贝时, 0 被拷贝为 2,1 被拷贝为 3,2 被拷贝为 4,结果与预期相符和,所以当目标空间与源空间重叠,但目标空间起始地址小于源空间时,采用从前向后一个字节一个字节的拷贝。

在这里插入图片描述

情况二:

  • 对应情况二使用从前向后一次拷贝字节时,将源空间内容拷贝到密目标空间,此时 4 被拷贝为 2 , 5 被拷贝为 3 , 6被拷贝为2。

  • 与预期结果并不相符和,预期拷贝后的结果时 0 1 2 3 2 3 4。

  • 实际结果为,0 1 2 3 2 3 2。

在这里插入图片描述

可以发现,使用从前向后一起拷贝字节时,源空间的内容覆盖掉,它还没有拷贝就已经被覆盖了,并将其放置在目标空间的最后一个位置。解决这种办法也很好理解,既然从前向后拷贝不行,那我们从后向前拷贝不久可以了。这样就避免了,还没有将源空间的数据拷贝到目标空间就被覆盖的情况。

将source指针和destination指针向后偏移num个字节 (char*)dest + num (char*)src + num,这样它两就指向最后一个字节,从后向前拷贝,每拷贝完一个字节后 num–

在这里插入图片描述

void* my_memmove(void* dest, const void* src, size_t num)
{
    void* ret = dest;
    assert(dest && src);
    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;
        }
	}
    return ret;
}

当dest > src时,从后向前,第一步将dest和src偏移到最后一个位置, (char*)dest + num (char*)src + num,然后进行赋值 ,

*((char *)dest ) = *((char *)src );,其代码内讲多块内容合并在一起操作,通过控制num大小,来控制了dest和src偏移的位置,而循环结束的条件的num为0,这样就有了一条很精简的代码。

memset

函数原型:

void* memset(void* ptr, int value, size_t num);
             被填充空间    改变的内容 设置的字节个数       

memset,是用来设置内存的,将内存以字节为单位,

  • 将每个字节设置为 value的内容

很朴素的用法,没有过多的变化,但结果往往会让人出乎意料~。

int main()
{
	int arr1[20] = { 1, 2, 3, 4, 5, 6 };
	int arr2[20] = { 0 };
	memset(arr2, 9, 5);
	memset(arr1, 8, 5);
	for (int i = 0; i < 6; i++)
	{
		printf("%d ", arr1[i]);
	}
    printf("\n");
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

这不是一个使用的案例,通过运行代码能够发现数组arr1和arr2的结果相当的大,这是因为memset是在字节上设置内容,这里的第一条memset语句,将数组arr2里的五个字节内容,都放置了一个数字9,而内存里的 09 09 09 09实际上是16进制数,0x09090909,所以在打印的结果上会很大。

数字arr1的结果,同数组arr2一样,即使在传递的数组这块内容已经放的有值,memset还会将其覆盖。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

这里以字符串为例,字符串的大小是一个字节,这里我试图将字符数组arr1里的前三个字节内容置为x。

int main()
{
	char arr1[10] = "abcdef";
	memset(arr1, 'x', 3);
	return 0;
}

在这里插入图片描述

观察结果,memset函数指哪打哪~,也没有在最后一个x后多余的放置 '\0'

memcmp

函数原型:

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

比较字节大小:

  • ptr1 > ptr2 返回大于0
  • ptr1 < ptr2 返回小于0
  • 等于返回 0
  • num是指比较字节个数

memcmp函数与字符串函数里的strncmp功能很类似,前者是通过比较字节大小,后者是比较字符大小。

int main()
{
	int arr1[] = { 1, 2, 5 };
	int arr2[] = { 1, 2, 6 };
	printf("%d \n", memcmp(arr1, arr2, 8));
	return 0;
}

arr1前12个字节:

01 00 00 00 02 00 00 00 05 00 00 00

arr2前12个字节

01 00 00 00 02 00 00 00 06 00 00 00

试图比较前8个字节的大小时,返回的结果是0,每个字节上的内容都是相等的,而 memcmp(arr1, arr2, 9);,比较前9个字节大小时,将返回小于0的数字, 06 > 05 。

cmp(arr1, arr2, 8));
return 0;
}
arr1前12个字节:

01 00 00 00 02 00 00 00 05 00 00 00

arr2前12个字节

01 00 00 00 02 00 00 00 06 00 00 00

试图比较前8个字节的大小时,返回的结果是0,每个字节上的内容都是相等的,而 memcmp(arr1, arr2, 9);,比较前9个字节大小时,将返回小于0的数字, 06 > 05 。

在这里插入图片描述

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

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

相关文章

STM32智能医疗监测系统教程

目录 引言环境准备智能医疗监测系统基础代码实现&#xff1a;实现智能医疗监测系统 4.1 数据采集模块 4.2 数据处理与控制模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;医疗监测与管理问题解决方案与优化收尾与总结 1. 引言 智能医疗监测系统通…

RocketMQ源码学习笔记:Producer发送消息流程

这是本人学习的总结&#xff0c;主要学习资料如下 马士兵教育rocketMq官方文档 目录 1、Overview2、验证消息3、查找路由4、选择消息发送队列4.1、选择队列的策略4.2、源码阅读4.2.1、轮询规避4.2.2、故障延迟规避4.2.2.1、计算规避时间4.2.2.2、选择队列 4.2.3、ThreadLocal的…

正运动控制器:EtherCAT总线初始化

1、EtherCAT总线初始化的目的 运动控制器的EtherCAT 总线接口可用于连接 EtherCAT 伺服驱动器和 EtherCAT 扩展模块&#xff0c;无论连接什么模块&#xff0c; EtherCAT 总线都需要编写一段 EtherCAT 总线初始化程序来进行电机和 EtherCAT 扩展模块的使能。使能之后的应用与脉…

QT多线程下,信号槽分别在什么线程中执行,如何控制?

可以通过connect的第五个参数进行控制信号槽执行时所在的线程 connect有几种连接方式&#xff0c;直接连接、队列连接和 自动连接 直接连接&#xff08;Qt::DirectConnection&#xff09;&#xff1a;信号槽在信号发出者所在的线程中执行 队列连接&#xff08;Qt::QueuedConn…

LeetCode-返回链表倒数第K个节点、链表的回文结构,相交链表

一、返回链表倒数第k个节点 . - 力扣&#xff08;LeetCode&#xff09; 本体思路参展寻找中间节点的方法&#xff0c;寻找中间节点是定义快慢指针&#xff0c;快指针每次走两步&#xff0c;慢指针每次走一步&#xff0c;当快指针为空或者快指针的下一个节点是空时&#xff0c;…

vue实现提交时对不同板块的表单内容进行校验

需求 1、需要对第一个红色框框板块内所有带星号的地方进行校验&#xff0c;并将提示语显示到对应的输入框下面&#xff0c;如图&#xff1a; 2、第二个红色框框板块中&#xff0c;点击 “添加相关人员” 能实现对多人的添加功能&#xff0c;并且能绑定相对应的校验规则 3、在…

linux进行redis的安装并使用RDB进行数据迁移

现在有两台电脑&#xff0c;分别是A&#xff0c;B&#xff0c;现在我要把A电脑上的redis的数据迁移到B电脑上&#xff0c;B电脑上是没有安装redis的 1.找到A电脑的redis的版本 1.先启动A电脑的redis&#xff0c;一般来说&#xff0c;都是直接在linux的控制台输入&#xff1a;re…

数据结构与算法(1):递归函数的设计技巧

1.前言 哈喽小伙伴们大家好哦~从今天开始笔者就要开始正式学习数据结构与算法了&#xff0c;在这里写知识博客既是做一些学习笔记&#xff0c;又相当于给大家做知识分享咯&#xff0c;希望大家一起加油哦&#xff01; 2.正文 2.1递归的引入 在正式讲解递归之前&#xff0c;…

创建鸿蒙手机模拟器(HarmonyOS Emulator)

文 | Promise Sun 一.前提条件&#xff1a; 鸿蒙项目开发需要使用模拟器进行开发测试&#xff0c;但目前想在DevEco Studio开发工具中使用模拟器就必须到华为官网进行报名申请&#xff0c;参加“鸿蒙模拟器&#xff08;HarmonyOS Emulator&#xff09;Beta活动申请”。 申请审…

中间件的理解

内容来源于学习网站整理。【一看就会】什么是前端开发的中间件&#xff1f;_哔哩哔哩_bilibili 每日八股文~白话说mq&#xff0c;消息中间件_哔哩哔哩_bilibili 例如&#xff1a; 1&#xff09;两个人打电话&#xff0c;中间的通信网络就是中间件。 2&#xff09;菜鸟驿站&…

SpringBoot以及swagger的基本使用

1、SpringBoot是什么&#xff1f; 一种快速开发、启动Spring的框架、脚手架 遵循“约定优于配置”的思想&#xff0c;使得能够快速创建和配置Spring应用 2、SpringBoot的核心特性 自动配置&#xff0c;一些依赖、默认配置都预设好了&#xff0c;减少了配置量起步依赖&#x…

ROS2-Navigation2初体验:Gazebo“打不开”

输入ros2 launch nav2_bringup tb3_simulation_launch.py headless:False后只能打开RVIZ而无法打开Gazebo的问题&#xff0c;多次尝试解决后发现只是多等待一会儿即可&#xff0c;在此给同样学习Navigation2的朋友们提个醒 。 Getting Started — Nav2 1.0.0 documentation 1…

Mindspore框架CycleGAN模型实现图像风格迁移|(二)实例数据集(苹果2橘子)

Mindspore框架&#xff1a;CycleGAN模型实现图像风格迁移算法 Mindspore框架CycleGAN模型实现图像风格迁移|&#xff08;一&#xff09;CycleGAN神经网络模型构建Mindspore框架CycleGAN模型实现图像风格迁移|&#xff08;二&#xff09;实例数据集&#xff08;苹果2橘子&#…

补充性文件

第一 二章 1&#xff0c;关系型数据库是什么&#xff1f;其中的关系是指什么&#xff1f; 答&#xff1a; 关系型数据库是一些相关的表和其他数据库对象的集合。数据模型符合满足一定条件的二维表格式。 2&#xff0c;E-R模型&#xff1f; 实体为表。用矩形表示。属性为字…

嵌入式物联网在工业中的应用——案例分析

作者主页: 知孤云出岫 目录 嵌入式物联网在工业中的应用——案例分析引言1. 智能工厂1.1 实时监控与数据采集 2. 智能物流2.1 库存管理 3. 智能维护3.1 设备故障预测 4. 智能交通4.1 交通流量监测 总结 嵌入式物联网在工业中的应用——案例分析 引言 嵌入式物联网&#xff08;…

回车不搜索直接页面刷新问题解决

使用技术栈&#xff1a;vue3、elementUiPlus 问题&#xff1a;回车触发方法&#xff0c;会刷新整个页面&#xff0c;不执行搜索 解决方法&#xff1a;在搜索的表单中增加submit.native.prevent submit.native.prevent

项目管理:不懂跟进,项目白做

在职场上&#xff0c;工作的本质其实就是信息的传递与处理。而信息的及时传递&#xff0c;也就是我们常说的及时跟进&#xff0c;往往被许多项目经理和职场人忽视。 他们或许在暗地里埋头苦干&#xff0c;却忽略了明面上的沟通与汇报&#xff0c;最终导致合作方和内部团队都对…

利用AI辅助制作ppt封面

如何利用AI辅助制作一个炫酷的PPT封面 标题使用镂空字背景替换为动态视频 标题使用镂空字 1.首先&#xff0c;新建一个空白的ppt页面&#xff0c;插入一张你认为符合主题的图片&#xff0c;占满整个可视页面。 2.其次&#xff0c;插入一个矩形&#xff0c;右键选择设置形状格式…

【SpringBoot】SpringCache轻松启用Redis缓存

目录&#xff1a; 1.前言 2.常用注解 3.启用缓存 1.前言 Spring Cache是Spring提供的一种缓存抽象机制&#xff0c;旨在通过简化缓存操作来提高系统性能和响应速度。Spring Cache可以将方法的返回值缓存起来&#xff0c;当下次调用方法时如果从缓存中查询到了数据&#xf…

JDK,JRE,JVM三者之间的关系

Java程序不是直接在操作系统之上运行&#xff0c;而是运行在JVM&#xff08;java虚拟机&#xff09;之上。 Java源代码&#xff08;.java文件&#xff09;经编译器编译成字节码&#xff08;.class文件&#xff09;&#xff0c;JVM本质上就是一个负责解释执行Java字节码的程序。…