C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇

这篇具有很好参考价值的文章主要介绍了C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

欢迎来到白刘的领域   Miracle_86.-CSDN博客

系列专栏  C语言知识

先赞后看,已成习惯

   创作不易,多多支持!

C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生

在C语言的内存管理领域,四大秘境之一的内存操作函数无疑为程序员提供了强大的工具。这些函数——memcpy、memmove、memset、memcmp——各自拥有独特的用途和特性,它们在内存操控中扮演着至关重要的角色。


目录

一、memcpy——内存的拷贝艺术

1.1 memcpy的使用

1.2 memcpy的模拟实现

1.3 重叠问题

二、memmove——内存的移动魔法

2.1 memmove的使用

2.2 memmove的模拟实现

 三、memset——内存的初始化神器

 四、memcmp——内存的比较之术


一、memcpy——内存的拷贝艺术

在前面我们讲了许多字符串函数:

C语言字符函数与字符串函数:编织文字的舞会之梦(上)-CSDN博客

C语言字符函数与字符串函数:编织文字的舞会之梦(下)-CSDN博客

其中我们发现strcpymemcpy非常相似,我们了解了str代表字符串,cpy代表copy,也就是拷贝,那mem是什么呢?其实它是memory的简写,memory我们都知道是记忆的意思,而它还有一个意思——内存。可以简单理解为计算机的记忆,那不就是内存嘛。那我们可以推断出来,memcpy,它的作用是用来拷贝内存的。

1.1 memcpy的使用

它的原型如下:

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

不难看出,它和strncpy的参数是一模一样的,没错,正是如此,只不过它可以copy任意类型的,而strncpy只能拷贝字符串。

1.原理:memcpy从source的位置开始,向后复制num个字节,到destination指向的内存的位置。

2.与strncpy不同的是,mem在遇到'\0'时不会停止。

3.使用需要包含头文件<string.h>。

#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	memcpy(arr2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr2[i]);
	}
	return 0;
}

运行结果:

C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生

1.2 memcpy的模拟实现

聊完它的基本原理以及使用后,我们再来看看它的模拟实现。

首先通过参数来看,我们传进去一个目的地,一个源头,还有字节数,那我可以这么写:

void* memcpy(void* dst, const void* src, size_t count)

接下来我们可以使用循环,次数为count,由于count是字节数,所以我们这里一个字节一个字节进行拷贝会比较容易操作。而void*类型的指针不可以解引用,我们需要进行强制类型转换,将其转换成char*,代码如下:

void* memcpy(void* dst, const void* src, size_t count)
{
	void* ret = dst;
	assert(dst);
	assert(src);
	/*
	* copy from lower addresses to higher addresses
	*/
	while (count--) {
		*(char*)dst = *(char*)src;
		dst = (char*)dst + 1;
		src = (char*)src + 1;
	}
	return(ret);
}

 这里返回ret(目标空间的首元素地址)是因为在memcpy中返回的也是这个:

C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生

但是问题出现了,如果目标空间和源头重叠了怎么办? 

1.3 重叠问题

我们来看下面一段代码:

#include <stdio.h>
#include <string.h>
#include<assert.h>
void* my_memcpy(void* dst, const void* src, size_t count)
{
	void* ret = dst;
	assert(dst);
	assert(src);
	/*
	* copy from lower addresses to higher addresses
	*/
	while (count--) {
		*(char*)dst = *(char*)src;
		dst = (char*)dst + 1;
		src = (char*)src + 1;
	}
	return(ret);
}
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	int arr2[10] = { 0 };
	my_memcpy(arr1+2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

我们可以看到目标空间与源头有重叠的部分,本来我们想把1,2,3,4,5拷贝到3,4,5,6,7的位置。

预期结果:1,2,1,2,3,4,5,8,9,10 

实际结果:C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生

这是为什么呢?这是因为在拷贝3的时候,3的位置已经是1了,3被覆盖掉了,其他的同理。这可怎么办呢?其实memcpy它被设计出来就是为了拷贝不重叠的情况的,如果它拷贝到重叠的部分,结果都是未定义的。那我们就没办法完成拷贝重叠部分了嘛?别着急,下面这个函数就可以解决这个问题。

二、memmove——内存的移动魔法

memmove和memcpy几乎是一模一样的,唯一的差别就是它可以处理重叠的源内存块和目标内存块。

2.1 memmove的使用

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

来看刚刚的问题的代码解决:

#include <stdio.h>
#include <string.h>
int main()
{
	int arr1[] = { 1,2,3,4,5,6,7,8,9,10 };
	memmove(arr1 + 2, arr1, 20);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr1[i]);
	}
	return 0;
}

运行结果:

C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生

它是怎么实现的呢?我们试着来模拟一下。

2.2 memmove的模拟实现

我们先来画图解析一下:

C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生

我们正常来讲是将1拷贝到3,2拷贝到4,是正着拷的。那如果我们反过来,先把5拷过去,倒着拷是不是就避免了被重叠覆盖的情况了。

这里有的人就耍小聪明了,就喜欢死记硬背了,正着拷不行,那就都倒着拷。

那再来看这张图:

C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生

如果我还是倒着拷的话,还是会覆盖。

所以我们得到了一个结论:当dest在src左面时,从前向后拷(正着拷);当dest在src右面时,从后向前拷(倒着拷)。

当你不理解的时候,画个图自己捋一下就好了。

思路有了,我们来看代码:

void* memmove(void* dst, const void* src, size_t count)
{
	void* ret = dst;
	if (dst <= src || (char*)dst >= ((char*)src + count)) {

		//正着拷形式如同memcpy

		while (count--) {
			*(char*)dst = *(char*)src;
			dst = (char*)dst + 1;
			src = (char*)src + 1;
		}
	}
	else {
		
        //倒着拷将首元素地址+字节数再-1即可指向最后一个字节。

		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);
}

 三、memset——内存的初始化神器

从名字上来看,set译为设置,那这个函数的作用大概率是设置内存的。

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

C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生

首先来看它的三个参数:

1.ptr:一个void*类型的指针,指向要被填充的内存块。

2.value:要设置的值。

3.num:字节的个数(设置多少个value的值,以字节为单位)

也就是说memset是⽤来设置内存的,将内存中的值以字节为单位设置成想要的内容。

 

它包含在头文件<string.h>中。

 因此memset经常被用来写游戏外挂。

我们来看代码实例:

#include <stdio.h>
#include <string.h>
int main ()
{
 char str[] = "hello world";
 memset (str,'x',6);
 printf(str);
 return 0;
}

运行结果:

C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生

切记:memset以字节为单位设置,若用于数组中,绝不是以元素为单位!!

 四、memcmp——内存的比较之术

经过这么多次的学习,我们已经对mem和cmp非常熟悉了,一个是内存,一个是比较。显然这个函数是用来比较两个内存块的大小的。

int memcmp(const void* ptr1, const void* ptr2, size_t num);
原理:⽐较从ptr1和ptr2指针指向的位置开始,向后的num个字节

返回值如下:

C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生 其实和strcmp相类似。

代码示例:

#include <stdio.h>
#include <string.h>
int main()
{
	char buffer1[] = "DWgaOtP12df0";
	char buffer2[] = "DWGAOTP12DF0";
	int n;
	n = memcmp(buffer1, buffer2, sizeof(buffer1));
	if (n > 0)
		printf("'%s' is greater than '%s'.\n", buffer1, buffer2);
	else if (n < 0)
		printf("'%s' is less than '%s'.\n", buffer1, buffer2);
	else
		printf("'%s' is the same as '%s'.\n", buffer1, buffer2);
	return 0;
}

来看运行结果:

C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇,C语言知识,c语言,开发语言,数据结构,学习方法,程序人生


 文章来源地址https://www.toymoban.com/news/detail-852883.html

到了这里,关于C语言内存操控的艺术探索:踏足四大秘境,铸就内存管理之巅峰传奇的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 探索C语言的内存魔法:动态内存管理解析

    ✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:C语言学习 贝蒂的主页:Betty‘s blog 通过前面的学习,我们已经掌握了两种开辟内存的方法,分别是: 但是静态开辟的空间明显有两个缺陷: 空间开辟⼤⼩是 固定 的。 数组在申明的时候,

    2024年02月19日
    浏览(32)
  • c++内存的四大分区详解

    目录 前言: 1、程序的基本运行流程 2,为啥要分为四个区域? 3,分为哪四个区域? 4,4个区域详解 代码区: 为什么会设置这两个功能呢? 全局区: 栈区: 堆区:  new: 补充知识:new 总结: 这篇博客介绍 c++四大分区 的详解,其中也会涉及到有关 new 的知识

    2024年02月20日
    浏览(29)
  • 探索艺术的新领域——3D线上艺术馆如何改变艺术作品的传播方式

    nbsp;nbsp;nbsp;nbsp;在数字化时代的浪潮下,3D线上艺术馆成为艺术家们展示和传播自己作品的新平台。不仅突破了地域和物理空间的限制,还提供了全新的互动体验。 nbsp;nbsp;nbsp;nbsp;一、无界限的展示空间:艺术家的新展示平台 nbsp;nbsp;nbsp;nbsp;3D线上艺术馆通过数字化技术,为艺

    2024年04月11日
    浏览(31)
  • 探索规律:Python地图数据可视化艺术

    使用 Pyecharts 构建地图可视化也是很简单的。Pyecharts 支持多种地图类型,包括普通地图、热力图、散点地图等。以下是一个构建简单地图的示例,以中国地图为例: 首先,确保已安装了Pyecharts 库。可以使用以下命令来安装: 然后,创建一个 Python 脚本,例如 map_example.py ,并

    2024年02月13日
    浏览(80)
  • 标题:探索AI绘画:使用深度学习生成艺术

    正文: 随着计算机技术的发展,人工智能在各个领域取得了显著的成果。 通过训练深度学习模型,AI可以学习大量的艺术作品,从而生成具有独特风格和创意的新作品。 本文将介绍如何使用 Python 和 TensorFlow 实现一个简单的AI绘画程序。   二、技术介绍 深度学习 :深度学习

    2024年04月11日
    浏览(28)
  • 探索PythonTurtle库:绘制美妙图形的艺术之旅

    导语: PythonTurtle库是一种强大的工具,可以将编程与艺术相结合,帮助你绘制出美妙的图形和动画。无论你是初学者还是有一定编程经验,本篇博客将详细介绍PythonTurtle库的基本概念、使用方法和一些创意示例。通过学习和探索,你将发现编程可以是一种有趣而富有创造力的

    2024年02月16日
    浏览(27)
  • 探索设计模式的魅力:抽象工厂模式的艺术

    抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,用于在不指定具体类的情况下创建一 系列相关或相互依赖的对象 。它提供了一个接口,用于创建 一系列“家族” 或 相关依赖对象 ,而无需指定它们的具体类。          主要参与者: 抽象工厂(Abstract Facto

    2024年01月19日
    浏览(36)
  • 探索Angular测试艺术:Angular Testing Recipes

    项目地址:https://gitcode.com/juristr/angular-testing-recipes Angular Testing Recipes是一个开源项目,由开发者Juri Strumpfloeger精心打造,旨在为Angular开发者提供一系列实用的测试策略和示例代码。该项目以GitCode为平台,以Markdown格式分享了关于单元测试、组件测试、服务测试等方面的实战技

    2024年04月22日
    浏览(23)
  • 深入理解并发编程艺术之内存模型

    随着硬件技术的飞速发展,多核处理器已经成为计算设备的标配,这使得开发人员需要掌握并发编程的知识和技巧,以充分发挥多核处理器的潜力。然而并发编程并非易事,它涉及到许多复杂的概念和原理。为了更好地理解并发编程的内在机制,需要深入研究内存模型及其在

    2024年02月14日
    浏览(38)
  • 探索Midjourney的艺术地图:常用画质关键词导航

    在这个由人工智能驱动的创意世界中,画质的控制成为了每一位创作者追求作品完美的关键。Midjourney提供了一系列的,让我们能够细致地调整我们心中所想象的场景与人物。从质感、明暗到风格,这些就像是调色盘上的色彩,每一次的选择与组合都能带来全新的

    2024年04月28日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包