手把手教你玩转内存函数(含模拟实现)

news2024/11/29 2:46:46

目录

一、memcpy

1.认识memcpy

2.使用memcpy

3.拓展:模拟实现memcpy

二、memmove

1.认识memmove

2.使用memmove

3.拓展:模拟实现memmove

三、memcmp

1.认识memcmp

2.使用memcmp

四、memset

1.认识memset

2.使用memset

3.拓展:模拟实现memset


一、memcpy

1.认识memcpy

以下关于函数定义的图片均出自:cplusplus.com - The C++ Resources Network 

memcpy函数的功能是从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中   memcpy的返回类型为void*,参数类型一个为void*,一个为const void*,还有一个是无符号整型即size_t   之所以一个用const修饰,另一个不用const修饰是因为我们要修改的目标只是dest所指向的内容,并不会修改到src所指向的内容。要注意一个点就是:这个函数操作的是字节,它不是根据你传递给它的那个类型来给予权限,它是一个字节一个字节的修改的。

2.使用memcpy

#include<stdio.h>
#include<string.h>//memcpy位于这个头文件中
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 4,3,1,2,6,8,7,11,10,9 };
	memcpy(arr1, arr2, 20);
   //将arr1所指向地址的20个字节一个一个转换为arr2所指向地址的20个字节
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}//将修改之后的数组打印出来
}

 

 

3.拓展:模拟实现memcpy

首先我们要明确我们这个函数要实现的目标,它的目标是将dest所指向地址的20个字节一个一个转换为src所指向地址的20个字节   那么我们的参数得有两个地址,这样才能访问dest和src所指向的内容并通过地址一个字节一个字节的访问,但我们并不知道用户会传递什么样的数据类型给我们,因此我们这两个数据的类型首先得是void*,又因为,我们只是对dest所指向的内容进行修改,src所指向的内容并不会被修改,故src参数的类型得是const void*接着我们还应该要有知道要拷贝多少个字节,因此我们还需要一个整型参数。

基本的框架已知,接下来就是实现

我们知道了两份数据的地址,一个是用来拷贝数据的数据,一个是拷贝内容,用来拷贝数据的数据得被转化为拷贝内容,又因为是一个字节一个字节的拷贝,所以在拷贝前,我们得把两个数据都强制类型转换为char*型的因为char*的操作权限为1个字节数,也就是+1只会跳过一个字节,这样便能够实现一个字节一个字节的将数据拷贝。

思路也有了,代码自然就出来了

#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* dest, const void* strc, size_t num)
{
	assert(dest && strc);//断言,避免使用者传递空指针
	int i = 0;
	for (i = 0; i < num; i++)//通过循环的方式一个字节一个字节的跳动
	{
		*((char*)dest + i) = *((char*)strc + i);//将对应的字节拷贝到目标数据上
	}
	return dest;//返回地址
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 4,3,1,2,6,8,7,11,10,9 };
	int a = 0;
	scanf("%d", &a);
	my_memcpy(arr1, arr1 + 2, a);
	//memcpy(arr1, arr2, 20);
	for (int i = 0; i < 10; i++)//通过循环将拷贝后的结果打印出来
	{
		printf("%d ", arr1[i]);
	}
}

二、memmove

1.认识memmove

memmove的作用其实和memcpy是一样的,唯一的区别则是memmove在地址有重叠的时候同样可以进行拷贝,而memcpy在内容有重叠的时候拷贝可能会出现问题   当然不一样的编译器实现memcpy也是不一样的,有的编译器对memcpy的实现和memmove的实现是一模一样的。等下我们就来展示,按我们方法写的memcpy在拷贝重叠内容时出现的问题。可以这么说memcpy能做的memmove也能做。memmove的返回类型为void*,三个参数两个为空类型的地址,其中一个地址所指向的内容不可改变(被const修饰),一个为无符号整型。

2.使用memmove

#include<stdio.h>
#include<string.h>
#include<assert.h>
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
    memmove(arr1 + 4, arr1 + 2, 20);
   //将该数组的3,4,5,6,7拷贝在该数组的5,6,7,8,9
	for (int i = 0; i < 10; i++)//通过循环将拷贝完成后的数据打印出来
	{
		printf("%d ",*(arr1+i));
	}
}

 那么之前为什么说我们的memcpy在拷贝重叠地址内容时会出错了,这里笔者画下图给大家解释一下,假设我们有这样一个整型数组

 那么当我们想将这儿的4,5,6,7拷贝成2,3,4,5,按之前的代码就应写成这副模样

#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memcpy(void* str1, const void* str2, int num)
{
	assert(str1 && str2);
	int i = 0;
	for (i = 0; i < num; i++)
	{
		*((char*)str1+i) = *((char*)str2+i);
	}
	return str1;
}
int main()
{
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,10 };
	my_memcpy(arr1+3, arr1+1, 16);
   //arr1+3的地址所指向的为该数组中的4,arr1+1所指向的为该数组中的2
   //16个字节为4个整型的长度
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
}

那按照我们之前所写的memcpy就是通过一个字节一个字节的变化先将4拷贝成2,再将5拷贝成3,这时停一下,我们看到第二张图

 此时此刻,数组应该是这般模样

 那么此时此刻你就会发现一个问题,我们的目标是将4,5,6,7拷贝成2,3,4,5也就是这样

但我们继续拷贝下去那就是将2,3,2,3上的后面两个2,3拷贝到6,7上呈现出来的就会是这般 

3.拓展:模拟实现memmove

核心问题已经说出来了,接下来就提一下解决方案,很简单,我们不难看出,有问题的其实就在重叠的部分,这里我直接说结论了,我们得先将重叠部分给拷贝到目标上再将其他的部分拷贝到目标上才是合理的   继续举我们之前的这个例子

 你想象一下,在拷贝的时候,我们先将5拷贝到6上,再将4拷贝到7上,再将2拷贝到4上,最后再将3拷贝到5上,也就是从后拷贝到前,还会有之前的问题吗?显然不会,另一种重叠的情况,就从前拷贝到后就行,不重叠的时候怎么来都行。总结一下,当dest<src时从前拷贝到后,当dest>src时从后拷贝到前,也就是我们这种情况,这个你得自己画下图才能完美的理解

上代码

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

三、memcmp

1.认识memcmp

memcmp的作用是在内存的存储层面上比较两个数据的大小,num为它们比较的字节个数   举个例子,如果我要比较两个整型数据,我就要传两个整型地址,同时还要传一个大小为4的整型变量(或者说无符号整型),如此才能够通过一个字节一个字节的比较从而得知是哪个整型大。当ptr1所指向地址的内容小于ptr2所指向的内容时返回一个小于0的数,大于返回大于0的数,等于返回0,跟之前strcmp接近    memcmp函数的返回类型为整型,参数为两个空类型指针和一个无符号整型,这两个空类型指针地址所指向的内容是不可被修改的(const),之所以这样设计因为我们只是比较大小,不需要改变对应内容的值。

2.使用memcmp

#include<stdio.h>
#include<string.h>//memcmp位于这个头文件中
int main()
{
	int a = 3;
	int b = 4;
	printf("%d",memcmp(&a, &b, 4));//将比较结果打印出来
}

 这里笔者就不对它进行模拟实现了,主要是不会,在尝试模拟的过程中,曾想过通过将数据强制类型转换成char*型的然后一个字节一个字节的比较,听上去很合理是吧,但是它有一个致命的问题,那就是权重问题,比方说7和11这两个数,设它们的类型是整型,那么它们的存储就是以二进制的形式进行存储的,在32位机器上它们的存储就是

00000000000000000000000000000111//7
00000000000000000000000000001011//11

但我们不可能一遇到不一样的就判断出这两个数据的大小,如果一遇到不一样的就判断,那就i会出现7大于11的搞笑情况。这个笔者实在不会搞,如果你们知道这个函数是怎么实现的,可以把相应链接发在评论区,非常感谢!

四、memset

1.认识memset

memset() 的作用是在一段内存块中填充某个给定的值,它的返回类型为空类型指针,三个参数类型,一个是地址,一个是整型,一个是无符号整型,memset的作用是将num个字节的数据非替换成value

2.使用memset

#include<stdio.h>
#include<string.h>//memset位于这个头文件中
int main()
{
	char arr1[] = "abc_def";
	memset(arr1,'x', 2);
//将arr1所给地址的内容,一个字节一个字节的修改成'x',共修改两个字节
	printf("%s", arr1);
}

 

 

3.拓展:模拟实现memset

#include<stdio.h>
#include<string.h>
void* my_memset(void*dest,int src,size_t num)
{
	int i = 0;
	for (i = 0;i<num; i++)
	{
		*((char*)dest + i) = (char)src;
    //通过强制类型转换和解引用,一个字节一个字节的实现目的
	}
	return dest;
}
int main()
{
	char arr1[] = "abc_def";
	//memset(arr1,'x', 3);
	my_memset(arr1, 'x',3);
	printf("%s", arr1);
}

好了,今天的分享到这儿就结束了,感谢各位友友的来访,祝各位友友前程似锦

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

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

相关文章

【网络编程】应用层协议——HTTP协议

文章目录 一、HTTP协议基本认识二、URL的认识2.1 urlencode和urldecode 三、HTTP协议格式3.1 HTTP请求与响应格式3.2 如何保证请求和响应被应用层完整读取&#xff1f;3.3 请求和响应如何做到序列化和反序列化&#xff1f;3.4 代码验证请求格式3.5 代码验证响应格式3.5.1 telne…

小程序开发及生态丰富,还需要App吗?

微信小程序自2017年推出以来&#xff0c;其生态系统得到了迅速的发展和壮大。作为中国最大的社交平台之一&#xff0c;微信拥有庞大的用户基础。微信小程序作为微信生态系统的一部分&#xff0c;自然而然地吸引了大量用户。据对公开资料进行统计&#xff0c;2021年全网小程序数…

校园跑腿小程序:为学生提供便捷的服务

随着社会的发展和人们生活水平的提高&#xff0c;高等教育越来越受到重视。大学校园不仅是学习的地方&#xff0c;也是学生们日常生活的场所。然而&#xff0c;在繁忙的学业和生活压力下&#xff0c;学生可能经常面临诸如代购、快递、取餐等各种琐碎但繁琐的任务。基于这个需求…

ModaHub魔搭社区:AI原生云向量数据库Zilliz Cloud与 Cohere 集成搭建智能问答系统

目录 准备工作 主要参数 准备数据 创建 Collection 插入数据 测试问答 本文将演示如何使用 Zilliz Cloud 和 Cohere 搭建基于 SQuAD 数据集 的问答系统。其中,Zilliz Cloud 负责提供向量数据库,Cohere 负责提供获取指定文字向量表示的接口。 准备工作 本示例中的脚…

黑马前端三大件

文章目录 1.html1.1 标题标签1.2 段落标签1.3换行标签1.4 水平分割线标签1.5 文本格式化标签1.6 图片标签1.7 音频标签1.8 视频标签1.9 链接标签的介绍1.10列表标签1.10.1 无序列表1.10.2 无序列表1.10.3 自定义列表 1.11表格属性1.11.1表格的基本标签1.11.2 表格相关属性1.11.…

使用layui滑块slider遇到问题解决:1、加标尺2、兼容移动端拖拽1、多个滑块使用赋值4、切换箭头赋值问题

使用layui框架 滑块组件 slider 时遇到的问题&#xff0c;以下图为例&#xff0c;我创建了一个总滑块和3个滑块&#xff0c;改变总滑块可以控制滑块123&#xff1a; 1、我的需求是加上标尺&#xff0c;layui没有该功能&#xff0c;自己写了一个简单的,代码在下面。 2、移动端…

Linux:输入输出流、重定向、管道命令

相关文章 Linux&#xff1a;chgrp、chown、chmod权限属性更改指令 Linux&#xff1a; 磁盘状态观察命令lsblk、blkid Linux&#xff1a;df、du容量查询指令 1、标准流文件 数据流重定定向由字面上的意思来看&#xff0c;就是将数据定向到其他地方去&#xff0c;事实也是如此…

ModaHub魔搭社区:非结构化数据范式转变和示例

目录 范式转变——非结构化数据 非结构化数据示例 范式转变——非结构化数据 既然我们对结构化数据和半结构化数据有了清晰的理解,现在让我们开始谈谈非结构化数据。与结构化数据和半结构化数据不同,非结构化数据可以采取任何形式,可以有任意大小或尺寸,并需要大量的运行…

ModaHub魔搭社区:AI原生云向量数据库Zilliz Cloud与 HuggingFace 集成搭建问答系统

目录 准备工作 主要参数 创建 Collection 插入数据 测试问答 本文将演示如何使用 Zilliz Cloud 和 HuggingFace 搭建问答系统。其中,Zilliz Cloud 负责提供向量数据库,HuggingFace 负责提供获取指定文字向量表示的接口。 准备工作 本示例中的脚本需要安装 pymilvus,…

寡头竞争和混合策略均衡

纯寡头的产量竞争 两家企业生产相同的产品,产量是决策变量,市场上只有一种价格。市场需求/Demand:P = 100 - (Q1+Q2) Q 是企业生产的产量 假设生产成本为0 这个案例可能存在的结果 (1)合谋 (2)古诺-纳什均衡 每个企业将它竞争对手的产量水平视为固定的,然后决定自己…

【C++学习笔记】C++如何规范C语言中的类型转换

C的类型转换 1 C语言中类型转换的缺陷2 为什么C要规范C的类型转换3 C强制类型转换3.1 static_cast3.2 reinterpret_cast3.3 const_cast3.4 dynamic_cast 1 C语言中类型转换的缺陷 在C语言中&#xff0c;如果赋值运算符左右两侧类型不同&#xff0c;或者形参与实参类型不匹配&a…

【kubernetes系列】Kubernetes之RBAC

概述 k8s的权限控制在实际工作中不那么经常使用&#xff0c;但是却是很重要的&#xff0c;我们需要深入理解才能很好的解决某些问题。在我们现目前的了解中&#xff0c;常用的授权插件有以下几种&#xff1a; Node&#xff08;节点认证&#xff09; ABAC(基于属性的访问控制) …

【UE4 C++】03-新建UE C++工程,新建C++类

UE版本&#xff1a;4.26 步骤 新建一个空白模板工程&#xff0c;选择C项目&#xff0c;选择项目名和项目存储位置&#xff0c;然后点击创建项目。 新建C类 选择父类为Character 命名&#xff0c;选择公有&#xff0c;然后点击创建类 等待编译完成 此时在Visual Studio中可以看…

源启:云原生计算架构的行业实现

7月5日&#xff0c;由工业和信息化部网络安全产业发展中心、中国软件行业协会等单位指导&#xff0c;中国电子主办的“麒麟傲天聚创未来2023操作系统产业大会”在京举行。中电金信研究院副院长陈书华在大会上发表主旨演讲。 陈书华认为数字经济已成为社会发展的重要引擎&#…

【论文解读】基于分层判断的 x264 快速模式选择算法

简介 题目&#xff1a; 基于分层判断的 x264 快速模式选择算法 原文&#xff1a; https://www.nstl.gov.cn/paper_detail.html?id77880ade9a55b3cc527192010242d90e 级别&#xff1a; EI 年份&#xff1a; 2010 年 机构&#xff1a; 上海交通大学 结论&#xff1a; 相比较 HE…

汽车+ChatGPT 车内生活体验再升级

这两年&#xff0c;人工智能工具ChatGPT爆火&#xff0c;在全球掀起了大模型之战。如今&#xff0c;最前沿的自然语言处理大模型应用到了人类的出行工具上&#xff0c;梅赛德斯-奔驰和微软官宣正在合作测试车载ChatGPT人工智能&#xff0c;并将面向约90万车主开启测试&#xff…

对象存储、数据库、NAS、标注数据集,均支持元信息配置|ModelWhale 版本更新

七月中旬&#xff0c;暑气渐浓&#xff0c;ModelWhale 新一轮的版本更新&#xff0c;期待为每个领域的你带来更好的使用体验。 本次更新中&#xff0c;ModelWhale 主要进行了以下功能迭代&#xff1a; • 新增 对象存储、数据库、NAS、标注数据的元信息展示&#xff08;专业版…

flutter开发实战-Theme主题切换

flutter开发实战-Theme主题切换 之前做的应用中有用到Theme主题切换&#xff0c;一直没有整理&#xff0c;这里整理一下。 使用的是Android studio 一、效果图 二、创建ThemeModel // 提供五套可选主题色 const _themes <MaterialColor>[Colors.blue,Colors.cyan,Co…

缓存 - Caffeine 不完全指北

文章目录 官网概述设计CodePOMPopulationEviction PolicyRefreshStatistics 官网 https://github.com/ben-manes/caffeine wiki: https://github.com/ben-manes/caffeine/wiki 概述 Caffeine是一个用于Java应用程序的高性能缓存框架。它提供了一个强大且易于使用的缓存库&a…

如何判定是否一份适合工作呢

核心指标&#xff1a;喜欢 春节仿佛还在昨天&#xff0c;转眼间2023年已经过半。分享和总结一下自己过去的这6个月吧&#xff01;你可以从以下几个方面展开谈谈。 23年上半年已经过去啦。结合工作多年经历简单写一写。 主要写自己&#xff1a; 工作非常努力&#xff0c;但是…