C语言内存函数的使用、剖析及模拟实现

news2024/11/24 12:31:11

目录

一、内存拷贝函数——memcpy

1.函数声明:

注意:

2.函数使用用例:

3.memcpy函数的模拟实现:

二、内存拷贝函数2——memmove

1.函数声明:

2.memmove函数的模拟实现

三、内存比较函数——memcmp

1.函数声明:

2.函数使用实例:

四、内存设置函数——memset

1.函数声明:

2,函数使用实例:


一、内存拷贝函数——memcpy

1.函数声明:

void * memcpy ( void * destination, const void * source, size_t num );

解释:

①:作用:将source所指向的空间的内容的前num个字节的内容拷贝到destination指向的空间。

②:该函数有三个参数:

第一个参数是个void*的指针,指向目的地空间;

第二个参数是个void*的指针,用于指向源头空间;

第三个参数类型为size_t,代表待拷贝的字节数。

③:该函数的返回类型为void*,即目标空间destination的起始地址。

④:该函数包含在头文件<string.h>中。

注意:

1.想到“拷贝”两个字,很多贴子可能会想到“strcpy”,但一定要注意,“strcpy”函数只能用于字符串拷贝,而“memcpy”函数可能拷贝不同类型的数据(int*、char*、...等等),所以我们还可以看到,该函数的形参的两个指针都是void*型,就是为了接收不同类型的数据。

2.memcpy函数只能用于处理不重叠的内存的拷贝(如将数组下标为1,2,3,4,5的内容拷贝到该数组下标为3,4,5,6,7的位置,这种情况下标为3,4,5的内存空间就是重叠了),否则会产生错误。重叠内存的拷贝由另外一个函数——memmove来实现,介绍在下文。

2.函数使用用例:

#include<stdio.h>
#include<string.h>
int main()
{
	//**********用例1***************************
	int arr1[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, sizeof(arr1));
	printf("arr2:");
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	printf("\n");
	//**********用例2****************************
	float arr3[5] = { 1.0,2.0,3.0,4.0,5.0 };
	float arr4[5] = { 0 };
	printf("arr4 ");
	memcpy(arr4, arr3, sizeof(arr3));
	for (int i = 0; i < 5; i++)
	{
		printf("%f ", arr4[i]);
	}
	return 0;
}

用例运行结果:

3.memcpy函数的模拟实现:

①:源代码

//函数模拟实现
#include<stdio.h>
#include<string.h>
#include<assert.h>

void* my_memcpy(void* dest, void* sour, size_t size)
{
	void* ret = dest;
	assert(dest && sour);
	while (size--)
	{
		*(char*)dest = *(char*)sour;
		dest = (char*)dest + 1;
		sour = (char*)sour + 1;
	}
	return ret;
}
int main()
{
	int arr1[5] = { 1,2,3,4,5 };
	int arr2[5] = { 0 };
	my_memcpy(arr2, arr1, sizeof(arr1));
	for (int i = 0; i < 5; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

解释:

①:因为是模拟实现,所以返回类型和参数类型都要相同。

②:因为返回值为目标空间的起始地址,所以开始先创建一个void*的指针将目标空间的起始地址dest保存起来。

②:因为void*指针不能用于加减和解引用操作,所以必须强制转换为其他类型的指针,所以就要思考转化为什么类型?因为是以字节为单位,所以很显然转为化char*指针就可以一字节一字节的拷贝。所谓拷贝无非就是赋值操作。

③:我们知道是以字节为单位进行拷贝,所以循环次数即为待拷贝字节数size,所以用一个while循环即可,循环体里面就是拷贝部分,先将两个指针转化为char*的指针,这样解引用的访问权限就是一个字节,这样依次赋值下去,最后在返回目标空间的起始地址ret即可。

二、内存拷贝函数2——memmove

1.函数声明:

void * memmove ( void * destination, const void * source, size_t num );

解释:

①:我们发现该函数的返回类型及参数类型和“memcpy”函数都是一样的,不难理解,因为两者都是内存的拷贝,只是“memmove”函数有一点更高级的功能,就是可以对重叠的内存进行拷贝。

2.memmove函数的模拟实现

#include<stdio.h>
#include<string.h>
#include<assert.h>
void* my_memmove(void* dest, void* sour, size_t sz)
{
	assert(dest && sour);
	void* ret = dest;
	if (dest < sour)
	{
		//前->后
		while (sz--)
		{
			*(char*)dest = *(char*)sour;
			dest = (char*)dest + 1;
			sour = (char*)sour + 1;
		}
	}
	else
	{
		//后->前
		while (sz--)
		{
			*((char*)dest+sz) = *((char*)sour+sz);
		}
	}
	return ret;
}

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

运行结果:

三、内存比较函数——memcmp

1.函数声明:

  

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

解释:

①:该函数的作用就是将ptr1所指向的内容和ptr2所指向的内容进行比较,同样以字节为单位,但要注意的是,是以字节为单位进行比较,第三个参数num就是待比较字节数。

②:注意别和字符串比较函数“strcmp”混淆,“strcmp”只能用于字符串的比较,而此函数可以进行不同类型的数据的比较。

②:比较规则:(可参考函数“strcmp”)

若前大于后,返回一个大于0的数字;

若前等于后,返回0;

若前小于后,返回一个小于0的数字。

2.函数使用实例:

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

很明显,arr1前四个数和arr2相同,但第五个数比arr2的第五个数小,所以会的到一个小于0的数,vs编译器默认这个小于0的数为-1,大于0的数为1.

四、内存设置函数——memset

1.函数声明:

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

①:函数的作用就是将ptr所指向的空间的内容的前num个字节的内容设置成第二个参数的值value,一定要注意是以字节为单位,可参考使用实例。

②:返回值为ptr指向的空间的起始地址。

2,函数使用实例:

本次知识到此结束,希望对你有所帮助!

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

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

相关文章

01_docker镜像管理:80分钟一口气学完docker+k8s!带你掌握docker+k8s所有核心知识点,全程干货,无废话!

docker镜像的实际使用学习 开发过程中&#xff0c;需要安装很多三方工具&#xff0c;比如etcd、kafka、mysql、nginx等等 1、下载安装Docker工具。 2、获取该软件的Docker镜像&#xff08;基本上&#xff0c;都能搜索到核实的镜像&#xff09;&#xff0c;下载镜像nginx镜像…

浏览器基本原理

1、浏览器内部组成 我们看到浏览器主要包括&#xff1a; 1个浏览器主进程&#xff1a; 主要负责界面显示&#xff0c;用户交互&#xff0c;子进程管理多个渲染进程&#xff1a;一般浏览器会为每个Tab标签窗口创建一个渲染进程&#xff0c;主要负责将html&#xff0c;css&#…

经典网络(一) AlexNet逐层解析 | 代码、可视化、参数查看!

文章目录 1 回顾2 AlexNet的重要性3 AlexNet解析3.1 结构3.1.1 CONV13.1.2 Max Pool13.1.3 NORM13.1.4 CONV23.1.5 Max Pool23.1.6 CONV3 CONV43.1.7 CONV53.1.8 Max Pool33.1.9 FC1 FC2 FC3 3.2 AlexNet使用到的技巧3.3 可视化3.4 代码实现模拟3.4.1 查看每一层输入输出3.4.2 …

UE 虚幻引擎 利用LOD,Nanite技术优化场景性能

目录 0 引言1 LOD1.1 LOD定义1.2 UE5中的LOD技术1.3 HLOD&#xff08;Hierarchical Level of Detail&#xff09; 2 Nanite2.1 UE5的Nanite技术2.2 Nanite介绍2.2.1 Nanite的优势2.2.2 Nanite网格体与传统静态网格体的不同2.2.3 Nanite支持的类型2.2.4 在地形中使用Nanite 0 引…

KT142C语音芯片flash型用户如何更新固件的说明_V2

目录 一、简介 2.1 让芯片进入PC模式 2.2 双击提供的exe程序即可 一、简介 正常的情况下&#xff0c;用户肯定是不需要更新固件的&#xff0c;因为芯片出厂默认就烧录了对应的程序固件&#xff0c;但是有客户可能需要小修小改&#xff0c;或者订制一下某些功能&#xff0c…

寻找环形链表的入环点

之前我们在判断一个链表是否为环&#xff0c; 是运用快慢指针的方法&#xff0c;且只能是慢指针走一步&#xff0c;快指针两步&#xff1b; 那么如何求带环链表的入环点的 思路一&#xff1a;数学方法&#xff08;找出带环链表各个特点量的关系&#xff09; 代码&#xff1a;…

Linux设备驱动之Camera驱动

Linux设备驱动之Camera驱动 Camera&#xff0c;相机&#xff0c;平常手机使用较多&#xff0c;但是手机的相机怎么进行拍照的&#xff0c;硬件和软件&#xff0c;都是如何配合拍摄到图像的&#xff0c;下面大家一起来了解一下。 基础知识 在介绍具体Camera框架前&#xff0c…

图像复原与重建,解决噪声的几种空间域复原方法(数字图像处理概念 P4)

文章目录 图像复原模型噪声模型只存在噪声的空间域复原 图像复原模型 噪声模型 只存在噪声的空间域复原

字节一面:你能手撕节流防抖吗?

前言 最近博主在字节面试中遇到这样一个面试题&#xff0c;这个问题也是前端面试的高频问题&#xff0c;节流防抖是前端性能优化一个很重要的手段&#xff0c;所以作为一个前端工程师必须要深入掌握这个知识点&#xff0c;博主在这给大家细细道来。 &#x1f680; 作者简介&…

01 TextRNN FastText TextCNN-04-训练要点,实验过程

TextRNN & FastText & TextCNN-03-模型总览&#xff0c;后 训练要点 RNN训练 得出来的y&#xff08;m&#xff09;&#xff08;预测标签&#xff09;是每一个分类的概率&#xff0c;比如是一个五分类&#xff0c;化成5个格子&#xff0c;每一个格子是概率&#xff0c…

java生成PDF的Util

java使用itext生成pdf-CSDN博客 接上文 支持表格绘制表格 支持表格中的文本 字体加粗、字体上色、单元格背景上色&#xff0c; 支持拼接文本 支持单行文本 多种背景颜色、字体上色 支持自定义水印 废话不说先上效果图 工具类代码 package com.zxw.文件.PDF.util;import …

建立一张表: 表里面有多个字段,每一个字段对应一种数据类

首先mysql -uroot -p 进入MySQL 选择一个数据库并使用 在该数据库内创建表格 create table homework_tb( id int(11) comment 编号, company_name char(6) comment 公司名称, introduce varchar(100) comment 介绍, content1 tinytext comment 内容1, co…

ad18学习笔记十一:显示和隐藏网络、铺铜

如何显示和隐藏网络&#xff1f; Altium Designer--如何快速查看PCB网络布线_ad原理图查看某一网络的走线_辉_0527的博客-CSDN博客 AD19(Altium Designer)如何显示和隐藏网络 如何显示和隐藏铺铜&#xff1f; Altium Designer 20在PCB中显示或隐藏每层铺铜-百度经验 AD打开与…

React【Context_作用、函数组件订阅Context、Fragments 、错误边界_概念 、错误边界_应用、Refs DOM】(四)

目录 Context_作用 函数组件订阅Context Fragments 错误边界_概念 错误边界_应用 Refs & DOM Context_作用 React组件中数据是通过 props 属性自上而下&#xff08;由父及子&#xff09;进行传递的&#xff0c;但是有的时候中间的一些组件可能并不需要props的值。 //A…

深度学习自学笔记一:神经网络和深度学习

神经网络是一种模拟人脑神经元之间相互连接的计算模型&#xff0c;它由多个节点&#xff08;或称为神经元&#xff09;组成&#xff0c;并通过调整节点之间的连接权重来学习和处理数据。深度学习则是指利用深层次的神经网络进行学习和建模的机器学习方法。 假设有一个数据集&a…

电阻的读数

常见电阻的阻值一般有色环电阻和贴片电阻 &#xff0c;下面介绍两种电阻的阻值读法。 1、色标法&#xff1a; 技巧&#xff1a;四环电阻的的精度一般为银色和金色&#xff0c;如果一眼能可看到这两种颜色可以判断为第4环的精度读数 可见棕色为第1环&#xff0c;黑色第2环&…

Three.js后期处理简明教程

后期处理&#xff08;Post Processing&#xff09;通常是指对 2D 图像应用某种效果或滤镜。 在 THREE.js 中我们有一个包含一堆网格物体的场景。 我们将该场景渲染为 2D 图像。 通常&#xff0c;该图像会直接渲染到画布中并显示在浏览器中&#xff0c;但我们可以将其渲染到渲染…

AI写文章软件-怎么选择不同的AI写文章软件

在如今信息爆炸的时代&#xff0c;无论是学生、职场人士&#xff0c;还是创作者和企业家&#xff0c;写文章都是一项常见而又重要的任务。然而&#xff0c;随着科技的不断进步&#xff0c;AI写文章的软件也逐渐走进了人们的视野。 147GPT批量文章生成工具​www.147seo.com/post…

Java 基于微信小程序的学生选课系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 文章目录 第一章&#xff1a; 简介第二章 技术栈第三章&#xff1a; 功能分析第四章 系统设计第五章 系统功…

Intel酷睿和AMD锐龙

Intel酷睿系列&#xff0c;主要分i3、i5、i7、i9 如&#xff1a;Intel 酷睿i5 10210U i5&#xff1a;品牌修饰符。 10&#xff1a;代次指示符。 210&#xff1a;sku编号。 常见后缀&#xff1a; G1-G7&#xff1a;集显等级。 U&#xff1a;低功耗。 H&#xff1a;标压版…