内存魔术师:精通内存函数的艺术

news2024/9/19 23:14:57

嘿嘿,家人们,今天咱们来详细剖析C语言中的内存函数,好啦,废话不多讲,开干!


目录

1.memcpy使用与模拟实现

1.1:memcpy的使用

1.2:memcpy的模拟实现

2:memmove的使用与模拟实现

2.1:memmove的使用

2.1.1:memcpy处理重叠空间

2.1.2:memmove处理重叠空间

2.2:memove的模拟实现

2.2.1:代码1(destination < source)

2.2.2:代码2(destination > source)

3:memset函数的使用

4:memcmp函数

4.1:代码1

4.2:代码2

4.3:代码3

1.memcpy使用与模拟实现

1.1:memcpy的使用

void memcpy(void * destination,const void * source,size_t num);
  • 函数memcpy从source的位置开始向后复制到num个字节的数据到destination指向的内存空间.
  • 这个函数在遇到'\0'的时候并不会停下来.
  • 如果source和detination有任何的重叠,复制的结果都是未定义的.
#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int main()
{
	int arr1[10] = { 0 };
	int arr2[] = { 1,2,3,4,5 };

	printf("拷贝前:");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}

	//第三个参数为要拷贝的字节数
	memcpy(arr1, arr2, 20);

	printf("\n");

	printf("拷贝后:");
	for(size_t i = 0; i < 10; i++)
	{
		printf("%d ",arr1[i]);
	}
	return 0;
}

 

1.2:memcpy的模拟实现

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <assert.h>
//
void * my_memcpy(void * destination,const void * source,size_t num)
{
	void* result = destination;

	//防止空指针的解引用
	assert(destination);
	assert(source);
	
	while(num--)
	{
		*(char*)destination = *(char*)source;
		//为什么不直接使用++
		/*
		* void * 是无具体类型的指针
		* void * 类型的指针能够存放任意数据类型的地址
		* void * 类型的指针不能对其进行解引用操作,也不能进行 +-整数的操作
		*/
		destination = (char*)destination + 1;
		source = (char*)source + 1;
	}

	return result;
}

int main()
{
	int arr1[10] = { 0 };
	int arr2[] = { 1,2,3,4,5,6,7,8,9,10};

	printf("拷贝前:");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}

	//第三个参数为要拷贝的字节数
	my_memcpy(arr1, arr2, 40);

	printf("\n");

	printf("拷贝后:");
	for(size_t i = 0; i < 10; i++)
	{
		printf("%d ",arr1[i]);
	}
	return 0;
}

 

2:memmove的使用与模拟实现

2.1:memmove的使用

void * memmove(void * destination,const void * source,size_t num);
  • 与memcpy的区别在于memmove函数在处理源内存空间和目标内存空间是可以重叠的.
  • 如果源空间和目标空间出现重叠,就得使用memmove函数来处理.

2.1.1:memcpy处理重叠空间

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <assert.h>
void* my_memcpy(void* destination, const void* source, size_t num)
{
	void* result = destination;

	//防止空指针的解引用
	assert(destination);
	assert(source);

	while (num--)
	{
		*(char*)destination = *(char*)source;
		//为什么不直接使用++
		/*
		* void * 是无具体类型的指针
		* void * 类型的指针能够存放任意数据类型的地址
		* void * 类型的指针不能对其进行解引用操作,也不能进行 +-整数的操作
		*/
		destination = (char*)destination + 1;
		source = (char*)source + 1;
	}

	return result;
}

int main()
{

	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	//memmove(arr+2, arr, 20);
	

	printf("拷贝前:");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	my_memcpy(arr + 2, arr, 20);

	printf("\n");

	printf("拷贝后:");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

2.1.2:memmove处理重叠空间

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <assert.h>
int main()
{

	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	

	printf("拷贝前:");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	memmove(arr+2, arr, 20);

	printf("\n");

	printf("拷贝后:");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	return 0;
}

2.2:memove的模拟实现

2.2.1:代码1(destination < source)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <assert.h>
void * My_Memmove(void * destination,const void *source,size_t num)
{
	void* result = destination;
	assert(destination);
	assert(source);
	//则从source的开始往detination的开始一步一步地向后拷贝
	if(destination < source)
	{
		while(num--)
		{
			//为什么不直接使用++
			/*
			* void * 是无具体类型的指针
			* void * 类型的指针能够存放任意数据类型的地址
			* void * 类型的指针不能对其进行解引用操作,也不能进行 +-整数的操作
			*/
			*(char*)destination = *(char*)source;
			destination = (char*)destination + 1;
			source = (char*)source + 1;
		}
	}
	else
	{
		destination = (char*)destination + num - 1;
		source = (char*)source + num - 1;
		//则从source的末尾往detination的末尾一步一步地向后拷贝
		while(num--)
		{
			//从后向前拷贝
			*(char*)destination = *(char*)source;
			destination = (char*)destination - 1;
			source = (char*)source - 1;
		}
	}
	return result;
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

	printf("拷贝前:");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	My_Memmove(arr, arr + 2, 16);

	printf("\n");

	printf("拷贝后:");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
}

2.2.2:代码2(destination > source)

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <assert.h>
void * My_Memmove(void * destination,const void *source,size_t num)
{
	void* result = destination;
	assert(destination);
	assert(source);
	//则从source的开始往detination的开始一步一步地向后拷贝
	if(destination < source)
	{
		while(num--)
		{
			//为什么不直接使用++
			/*
			* void * 是无具体类型的指针
			* void * 类型的指针能够存放任意数据类型的地址
			* void * 类型的指针不能对其进行解引用操作,也不能进行 +-整数的操作
			*/
			*(char*)destination = *(char*)source;
			destination = (char*)destination + 1;
			source = (char*)source + 1;
		}
	}
	else
	{
		destination = (char*)destination + num - 1;
		source = (char*)source + num - 1;
		//则从source的末尾往detination的末尾一步一步地向后拷贝
		while(num--)
		{
			//从后向前拷贝
			*(char*)destination = *(char*)source;
			destination = (char*)destination - 1;
			source = (char*)source - 1;
		}
	}
	return result;
}

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

	printf("拷贝前:");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	My_Memmove(arr + 3, arr + 1, 16);

	printf("\n");

	printf("拷贝后:");
	for (size_t i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}
}

3:memset函数的使用

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

memset是用来设置内存的,将内存中的值以字节为单位设置成想要的内容.

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int main()
{
	char str[] = "hello world";
	memset(str, '7', 6);
	printf("%s\n",str);
	return 0;
}

4:memcmp函数

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

该函数的功能是:从ptr1和ptr2指针的位置开始进行比较,比较的字节个数为num个. 

4.1:代码1

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[] = "SerenityNow987";
	char str2[] = "SeZIRIQWXMW987";
	int result = memcmp(str1, str2, sizeof(str1));
	if (result > 0)
		printf("%s > %s", str1, str2);
	else if (result == 0)
		printf("%s == %s", str1, str2);
	else
		printf("%s < %s", str1, str2);
	return 0;
}

4.2:代码2

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[] = "SerenityNow987";
	char str2[] = "SezIRIQWXMW987";
	int result = memcmp(str1, str2, sizeof(str1));
	if (result > 0)
		printf("%s > %s", str1, str2);
	else if (result == 0)
		printf("%s == %s", str1, str2);
	else
		printf("%s < %s", str1, str2);
	return 0;
}

4.3:代码3

#define  _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>

int main()
{
	char str1[] = "SerenityNow987";
	char str2[] = "SerenityNow987";
	int result = memcmp(str1, str2, sizeof(str1));
	if (result > 0)
		printf("%s > %s", str1, str2);
	else if (result == 0)
		printf("%s == %s", str1, str2);
	else
		printf("%s < %s", str1, str2);
	return 0;
}

好啦,uu们,C语言的内存函数这部分滴详细内容博主就讲到这里啦,如果uu们觉得博主讲的不错的话,请动动你们滴小手给博主点点赞,你们滴鼓励将成为博主源源不断滴动力,同时也欢迎大家来指正博主滴错误~

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

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

相关文章

【机器学习随笔】基于kmeans的车牌类型分类注意点

kmeans是无监督的聚类算法&#xff0c;可用于数据的分类。本文尝试用kmeans对车牌类型进行分类&#xff0c;记录使用过程中的注意点。 kmeans使用过程中涉及两个大部分&#xff0c;模型与分析。模型部分包括训练模型和使用模型&#xff0c;分析部分主要为可视化分析。两部分的主…

这东西有点上头,不小心刷到天亮了。。。

相信很多每天勤奋刷题的小伙伴已经发现了&#xff0c;面试鸭又又又升级更新了&#xff01; 打开首页就让人眼前一亮&#xff0c;优化了岗位分类导航栏&#xff0c;找起目标题库更轻松了。毕竟鸭鸭目前已经有 6000 道面试题、上百个题库&#xff0c;一不小心就会淹没在浩瀚题海…

如何优化MySql的性能

优化MySQL的性能是一个复杂但至关重要的任务&#xff0c;它涉及到多个层面的调整和优化。以下是一些关键的步骤和策略&#xff0c;可以帮助你提高MySQL数据库的性能&#xff1a; 1. 优化数据库设计 选择合适的数据类型&#xff1a;确保你使用的数据类型是适合你的数据的&#…

Three.js 实战【4】—— 3D地图渲染

初始化场景&准备工作 在vue3threejs当中&#xff0c;初始化场景的代码基本上是一样的&#xff0c;可以参考前面几篇文章的初始化场景代码。在这里进行渲染3D地图还需要用到d3这个库&#xff0c;所以需要安装一下d3&#xff0c;直接npm i即可。 再从阿里云这里提供的全国各…

SQL server 6.5升级到SQL server 2019的方法

背景&#xff1a; 对日项目&#xff0c;客户的旧系统的数据库用的是SQL server 6.5&#xff0c;操作系统是windows NT。新系统要求升级到SQL server 2019&#xff0c;查了下资料发现旧系统的版本实在是太久远了&#xff0c;90年代的。 数据库部分的升级思路是这样的&#xff…

git 更新LingDongGui问题解决

今天重新更新灵动gui的代码&#xff0c;以便使用最新的arm-2d&#xff0c;本来以为是比较简单的一件事情&#xff08;因为以前已经更新过一次&#xff09;&#xff0c;却搞了大半天&#xff0c;折腾不易啊&#xff0c;简单记录下来&#xff0c;有同样遇到问题的同学参考&#x…

AI算法部署方式对比分析:哪种方案性价比最高?

随着人工智能技术的飞速发展&#xff0c;AI算法在各个领域的应用日益广泛。AI算法的部署方式直接关系到系统的性能、实时性、成本及安全性等多个方面。本文将探讨AI算法分析的三种主要部署方式&#xff1a;本地计算、边缘计算和云计算&#xff0c;并详细分析它们的优劣性。 一、…

基于vue框架的宠物交流平台1n2n3(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。

系统程序文件列表 项目功能&#xff1a;会员,宠物信息,宠物类型,团队信息,申请领养,团队申请,领养宠物 开题报告内容 基于Vue框架的宠物交流平台开题报告 一、项目背景 随着现代生活节奏的加快与人们情感需求的日益增长&#xff0c;宠物已成为众多家庭不可或缺的重要成员。…

基于Python的影视数据可视化---附源码75141

摘 要 本文基于Python语言&#xff0c;设计并实现了一个影视数据可视化系统&#xff0c;包括首页、公告通知、新闻资讯和电影信息等功能模块。通过对影视数据的采集、处理和可视化展示&#xff0c;该系统旨在为用户提供全面的影视信息和数据分析服务。在研究背景中&#xff0c…

编译运行 webAssembly(wasm)

环境准备&#xff1a; lunix下docker 参考https://hub.docker.com/r/emscripten/emsdk 拉编译环境 docker pull emscripten/emsdk 编译 随便找个目录&#xff0c;敲下面命令&#xff0c;编译一个webAssembly 程序 # create helloworld.cpp cat << EOF > hellowo…

Android Studio 新生成key store 打包apk报 Invalid keystore format

Android Studio 新生成key store 打包apk报错 Execution failed for task :app:packageDebug. > A failure occurred while executing com.android.build.gradle.internal.tasks.Workers$ActionFacade > com.android.ide.common.signing.KeytoolException: Failed …

充电宝什么品牌比较好用?2024年最值得推荐充电宝品牌!

近年来&#xff0c;随着电子设备使用需求的增加&#xff0c;充电宝市场呈现出蓬勃发展的态势。优秀的充电宝产品不仅能够提供稳定的充电速度&#xff0c;还具备方便携带的体验&#xff0c;深受用户喜爱。然而&#xff0c;面对市场上众多品牌和型号的选择&#xff0c;如何找到最…

C++库std::clamp

C库std::clamp std::clamp: 轻松掌握值的范围限制 目录 1. 引言2. std::clamp 基本概念2.1 函数签名2.2 参数说明2.3 返回值 3. 基本用法4. 深入理解 std::clamp4.1 实现原理4.2 注意事项 5. 高级用法5.1 自定义比较函数5.2 与 lambda 表达式结合 6. 实际应用场景6.1 图形编程…

全球安防监控、工业检测摄像机市场规模情况一览

一、全球安防监控市场规模情况综合分析 &#xff08;1&#xff09;全球安防监控摄像机市场规模 全球市场研究公司Research Nester统计&#xff0c;2023年全球安防监控摄像机市场规模为811.1亿元&#xff0c;预测到2028年&#xff0c;全球安全与监控市场规模预计将达到1869.3亿…

将 Parallels Desktop(PD虚拟机)安装在移动硬盘上,有影响吗?

当我们谈论在移动硬盘上安装 Parallels Desktop&#xff08;简称PD虚拟机&#xff09;及其对性能的影响时&#xff0c;特别是在运行如Unigraphics这样的资源密集型软件时&#xff0c;用户需要在便携性与性能之间找到最佳平衡。本文将深入探讨PD虚拟机装在移动硬盘有影响吗&…

(javaweb)mysql---DDL

一.数据模型&#xff0c;数据库操作 1.二维表&#xff1a;有行有列 2. 3.客户端连接数据库&#xff0c;发送sql语句给DBMS&#xff08;数据库管理系统&#xff09;&#xff0c;DBMS创建--以文件夹显示 二.表结构操作--创建 database和schema含义一样。 这样就显示出了之前的内容…

类和对象(中)【上篇】(构造,析构,拷贝函数)

&#x1f31f;个人主页&#xff1a;落叶 目录 类的默认成员函数 构造函数 无参构造 带参构造函数 全缺省构造函数 析构函数 对⽐C和C解决括号匹配问题 C语言版的Stack C版的Stack 拷⻉构造函数 类的默认成员函数 默认成员函数就是⽤⼾没有显式实现&#xff0c;编译器会…

如何查看微信聊天记录,防员工私单(有效监管员工电脑微信聊天的方法)

在企业管理中&#xff0c;防止员工私单&#xff08;即员工绕过公司直接与客户交易&#xff09;是管理中的一大难题。 许多员工使用微信进行日常工作沟通&#xff0c;而如果管理不到位&#xff0c;容易产生私单问题&#xff0c;影响企业的利益。 为了解决这一问题&#xff0c;…

【自费2W真机测评】三款热门/旗舰宠物空气净化器米家、希喂、352对比试用!

我家老大是三个月大的时候接回来的&#xff0c;接回来前就是家教好的小猫咪一只&#xff0c;不乱尿、不掉毛的。看朋友家都被猫咪掉毛困扰着&#xff0c;我还嘚瑟觉得自己养可好了&#xff0c;根本不掉毛。养了三个月老大长成大猫猫了&#xff0c;我又觉得我可以了&#xff0c;…

浏览器插件快速开启/关闭IDM接管下载

假设你已经为浏览器安装了IDM扩展&#xff0c;那么按下图的点击顺序&#xff0c;可以快速开启或关闭IDM的下载接管&#xff0c;而不必在IDM软件的设置->选项中&#xff0c;临时作调整。