【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!

这篇具有很好参考价值的文章主要介绍了【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!,《C语言进阶篇》,c语言,开发语言,算法,动态规划

🎬 鸽芷咕:个人主页

 🔥 个人专栏:《C语言初阶篇》 《C语言进阶篇》
⛺️生活的理想,就是为了理想的生活!

前言

   🌈hello! 各位宝子们大家好啊,又是新的一天开始了,今天给大家带来的是动态内存规划这一章节!
   ⛳️我们在创建变量的时候大家都知道大小是固定,不够灵活。而动态内存分配可以改变这一现象!当我们需要多少就可以规划多少,而不需要时就可以释放掉,这样是不是就可以极大地避免了内存的浪费!
   📚本期文章收录在《C语言高阶篇》,大家有兴趣可以看看呐
  ⛺️ 欢迎铁汁们 ✔️ 点赞 👍 收藏 ⭐留言 📝!

💬 为什么存在动态内存分配

  ⛳️在前面内容中我们学的开辟空间大多都是用数据类型直接创建空间。

  • 比如用整形开辟一个大小为4个字节的空间
  • 或者数组开辟一个连续的储存空间
  • 而这些临时变量大多都是存放在栈区的
    🔥 注:在前面C/C++中内存大致分的三个区域有讲过《C/C++的三个内存区域》
int main()
{
	int a = 0;//在栈空间上开辟四个字节
	int arr[40]={0};//在栈空间上开辟40个字节
}

但是这的开辟空间的方式有两个缺点:

  • 数组空间申请多了,如果没有用完就会照成空间的浪费!
  • 空间开辟大小是固定的

所以像以前的空间开辟方法满足不了我们的需求,那么有没有我们想开辟多少空间就开辟多少,而当我们不想要的时候还可以释放!这个时候就需要动态内存开辟了!

💬 动态内存函数的介绍

  ⛳️ 而动态内存开辟就需要用到相关的函数分别是: malloc free calloc realloc 把这四个函数只要掌握就可以完全的掌握动态内存分配了,下面我们就详细给大家介绍介绍:

1️⃣ 动态内存函数 malloc

动态内存开辟的函数: malloc

void* malloc (size_t size);

这个函数向内存申请一块 连续可用 的空间,并返回指向这块空间的指针。

  • 如果开辟成功,则返回一个指向开辟好空间的指针。
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
  • 返回值的类型是 void* ,所以 malloc 函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
  • 如果参数 size0malloc 的行为是标准是未定义的,取决于编译器。

⛳️ 好了malloc的使用方法给大家介绍了,接下来就是给大家介绍介绍这个这个函数如何使用:

  • 他们的库函数都是 #include <stdlib.h>
  • 所以使用的时候一定要记得加头文件哦!
#include <stdio.h>
#include <stdlib.h>
int  main()
{
	int arr[10] = { 0 };
	malloc(40);
	return 0;
}

我们都知道数组创建的空间是连续,而malloc申请的空间也是连续的但是malloc的空间是没有类型的。

  • 那么我们想像数组一样访问整形4个字节来访问怎么办呢?
  • 很简单我们把 malloc 的返回值类型强制转换为 int*
  • 整形指针接收 malloc 的返回值就可以
#include <stdio.h>
#include <stdlib.h>
int  main()
{
	int arr[10] = { 0 };
	int* p=(int*)malloc(40);
}

这样我们就可以和整形数组一样存放整形了,因为指针解引用每次也跳过4个字节

💭 malloc 函数返回失败怎么办

如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。

  • 如果开辟失败,就会给 p 返回NULL 空指针
  • 而我们一旦对空指针在进行访问不会,越界访问越界了嘛?
  • 而这是绝对不允许的,一旦越界就会导致程序崩溃⁉️
  • 所以我们加一段代码来保证程序的安全性
int  main()
{
	int arr[10] = { 0 };
	int* p = (int*)malloc(40);
	//开辟失败
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	return 0;

这样就就可以在开辟失败时及时避免错误,直接return返回让程序结束!

  • 这里开辟失败是,让库函数 perror 给我们提示一下
  • malloc 里面出现了什么错误!
  • 下面就给大家观察一下开辟失败是什么样的

📑图片展示:
【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!,《C语言进阶篇》,c语言,开发语言,算法,动态规划

⛳️ 大家看这里当我们申请的空间太大是开辟不了就会给我们返回空间不够的错误提示

  • ps:申请的空间一定要非常大不然测试就不会返回错误值的
  • 博主试了好几遍还以为是自己的代码问题结果是申请空间太小了

💭 malloc 是在哪里开辟空间的

⛳️我们都知道临时变量是存放在栈空间的,那么malloc申请的空间是哪里的呢?

📚 代码演示:

#include <stdio.h>
#include <stdlib.h>
int  main()
{
	int arr[10] = { 0 };
	int* p = (int*)malloc(40);
	//开辟失败
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	 
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	return 0;
}

📑 代码结果:
【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!,《C语言进阶篇》,c语言,开发语言,算法,动态规划

  ⛳️这里打印的就是我们申请空间的值,但由于malloc函数并不会给我们初始化所以里面存放的都是随机值。

  • 那么这里面的动态内存分布到底是什么样呢?
  • 为什么里面全部都是随机值呢?
  • 这个图片来告诉你一切

【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!,《C语言进阶篇》,c语言,开发语言,算法,动态规划

  ⛳️我们动态内存分配都是在堆区开辟空间的, p 指针变量是在栈区里面开辟的空间里面。所以当malloc在返回时返回了起始地址然后我们用 p 接收了malloc申请空间的起始地址

  • 但是,malloc这个函数只返回起始地址并不进行初始化

💭 malloc申请空间为0

  ⛳️ 做为一个程序员我们在想要申请空间的时候肯定是已经知道,要申请多少空间。你又要malloc申请空间,又只申请0个空间,这种行为本来就是不合理,所以我们在使用malloc时要避免这种情况以免出现不必要的错误!

  • 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
📆 malloc申请空间会主动释放嘛

  ⛳️而malloc申请的空间,当程序退出时,才会还给操作系统,而当程序未结束时,动态内存申请的内存空间,是不会主动释放的。这样就会照成内存的浪费!

  • 这时就需要使用free来释放,我们申请的动态内存空间
  • 编程的好习惯是,每次使用完malloc都要使用free释放空间
  • 下面我们就来介绍一下free函数

2️⃣ 动态内存函数 free

  ⛳️C语言提供了另外一个函数 free ,专门是用来做动态内存的释放和回收的,函数原型如下:

  • void free (void* ptr);

free函数用来释放动态开辟的内存。

  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
  • 如果参数 ptr 是NULL指针,则函数什么事都不做。

⛳️ 好了free的参数详情给大家介绍了,接下来就是给大家介绍介绍这个这个函数如何使用:

📚 代码演示:

#include <stdio.h>
#include <stdlib.h>
int  main()
{
	int arr[10] = { 0 };
	int* p = (int*)malloc(40);
	//开辟失败
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	 
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

  ⛳️ 这就是 free 的使用方法了,是不是非常简单。只需要把我们指针变量 p 传给 free 函数,因为 p 里面存放了 malloc 申请空间的起始地址,那么为什么还要把 p 给置为空指针呢?

  • 因为我们虽然把指针p记录的动态空间给释放了
  • 但是p本身不会被释放,而p里面存放的地址就成 野指针
  • 这个情况是非常不安全的所以我们把它置为空!
💭 内存函数 free的错误使用

如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。

  • 这种行为是不被允许的,希望大家使用时注意!

📚 代码演示:

int main()
{
	int a = 10;
	int* p = &a;
	free(p);//err
	return 0;
}

📑 代码结果:
【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!,《C语言进阶篇》,c语言,开发语言,算法,动态规划

3️⃣ 动态内存函数 calloc

  ⛳️ C语言还提供了一个函数叫 calloccalloc 函数也用来动态内存分配。其实非常简单这个函数和 malloc 的功能是一样的,只不过会把申请的空间初始化为 0

函数原型如下:

void* calloc (size_t num, size_t size);
  • 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
  • 与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0。

📜举个例子:

#include <stdio.h>
#include <stdlib.h>
int  main()
{
	int arr[10] = { 0 };
	int* p = calloc(10,sizeof(arr[0]));
	//开辟失败
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	//开辟成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

📑 代码结果:

【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!,《C语言进阶篇》,c语言,开发语言,算法,动态规划

  ⛳️ 这里就不给大家过多描述了,这个函数和malloc的使用大致一样!好的习惯是每次申请的动态空间在用完的时候都要释放掉!

4️⃣ 动态内存函数 realloc

  ⛳️有人会说不是动态内存可大可小嘛?想要多少空间就要多少,不想要了就可以缩小!前面的函数只能开辟和释放并不能控制大小啊?下面我们就给大家介绍介绍realloc函数它就完美的实现了这些功能。

  • 而想熟练的使用realloc函数就得知道
  • realloc开辟内存的三种情况

realloc 函数函数原型如下:

void* realloc (void* ptr, size_t size);

💭 内存函数 free的参数说明

realloc函数的出现让动态内存管理更加灵活:
void* realloc (void* ptr, size_t size);

  • ptr 是要调整的内存地址
  • size 调整之后新大小
  • 返回值为调整之后的内存起始位置。
  • 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 新 的空间。

📚 代码演示:

#include <stdio.h>
#include <stdlib.h>
int  main()
{
	int arr[10] = { 0 };
	int* p = calloc(10,sizeof(arr[0]));
	//开辟失败
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	//开辟成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	//增加空间
	realloc(p, 80);

	free(p);
	p = NULL;
	return 0;
}

这就是realloc的用法当我们说开辟的空间只有40个大小不够用了。那么就可以用realloc去增加为80个字节大小!

💭 内存函数 free的3种使用情况

✅情况一

⛳️ 第一种情况就是后面的连续空间足够,我们我们就会在后给连续的新开辟40个字节使其增加为80个字节大小!

  • 下面给大家看看看内存分布情况图

📚 代码演示:

#include <stdio.h>
#include <stdlib.h>
int  main()
{
	int arr[10] = { 0 };
	int* p = calloc(10,sizeof(arr[0]));
	//开辟失败
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	//开辟成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	//增加空间
	realloc(p, 80);

	free(p);
	p = NULL;
	return 0;
}

📑图片展示:

这就是第一种情况的内存分布,当后面的空间足够时后给连续的新开辟40个字节使其增加为80个字节大小

【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!,《C语言进阶篇》,c语言,开发语言,算法,动态规划

✅情况二

  ⛳️当我们想用reaclloc增加空间时,但是后面空间不够了就会重新开辟新空间并将原来空间的内容拷贝到新空间,并且将旧空间释放掉.

【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!,《C语言进阶篇》,c语言,开发语言,算法,动态规划
这里我们思考一个问题,realloc也会返回失败那么就会返回NULL空指针!

  • 本来我p指针变量还维护40个字节的大小结果你给一个空指针
  • 那么我不仅新空间没开辟,旧空间也丢了,

这样就会造成内存泄漏的问题,所以我们在这里就不敢用p接收我们的realoc返回值,需要进行代码改进!

📚 代码演示:

#include <stdio.h>
#include <stdlib.h>
int  main()
{
	int arr[10] = { 0 };
	int* p = calloc(10,sizeof(arr[0]));
	//开辟失败
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	//开辟成功
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d\n", p[i]);
	}
	//增加空间
	int* ptr = realloc(p, 80);
	if (ptr != NULL)
	{
		p = ptr;
		ptr=NULL;
	}
	else
	{
		perror("realloc");
	}

	free(p);
	p = NULL;
	return 0;
}

这样就可以避免我们上面说的错误了,如何 realloc 开辟失败我们就不接收空指针。

  • if判断完了之后再决定接不接收就完美解决问题
✅ realloc如何减少空间

  ⛳️ 这个不就更加简单了嘛?前面说了我们realloc函数可以动态开辟空间可大可小!那么使动态内存变小不就是更加简单了嘛?直接把内存改小不就行了.

  • 下面就来演示一下如何使动态内存变小

📚 代码演示:

#include <stdio.h>
#include <stdlib.h>
int  main()
{
	int arr[10] = { 0 };
	int* p = calloc(10,sizeof(arr[0]));
	//开辟失败
	if (p == NULL)
	{
		perror("calloc");
		return 1;
	}
	//减少空间
	int* ptr = realloc(p, 20);
	if (ptr != NULL)
	{
		p = ptr;
	}
	else
	{
		perror("realloc");
	}

	free(p);
	p = NULL;
	return 0;
}

📑 代码结果:
【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!,《C语言进阶篇》,c语言,开发语言,算法,动态规划

⛳️这里就可看到我们把malloc申请的动态空间40个字节,改变成了20个字节!

✈️ 总结

✅ 归纳:
好了以上就是关于动态内存分配函数 malloc free calloc realloc 4个动态内存分配函数的全部用法了!
  malloc的介绍和使用方法
  free的介绍和使用方法
  calloc和malloc的区别
  realloc语句使用的2种情况
☁️ 把这些内存函数掌握完,你就可以完美的使用动态内存分配了快去试试吧!
看到这里了还不给博主扣个:
⛳️ 点赞☀️收藏 ⭐️ 关注

💛 💙 💜 ❤️ 💚💓 💗 💕 💞 💘 💖
拜托拜托这个真的很重要!
你们的点赞就是博主更新最大的动力!
有问题可以评论或者私信呢秒回哦。
【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!,《C语言进阶篇》,c语言,开发语言,算法,动态规划文章来源地址https://www.toymoban.com/news/detail-579022.html

到了这里,关于【C语言高阶篇】成为编程高手必学内容,动态内存分配我不允许还有人不会!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 【C语言高阶篇】结构体 —— 什么是内存对齐?

    🎬 鸽芷咕 :个人主页  🔥 个人专栏 :《C语言初阶篇》 《C语言进阶篇》 ⛺️生活的理想,就是为了理想的生活!    🌈 hello! 各位宝子们大家好啊,今天给大家带来的是结构体的内存对齐这部分知识,可以说是干货满满啦!    ⛳️ 在我们C语言的面试题中,结构体最

    2024年02月14日
    浏览(46)
  • 【C语言高阶篇】C语言面试必考知识点,结构体的内存对齐我看还有谁不会!

    🎬 鸽芷咕 :个人主页  🔥 个人专栏 :《C语言初阶篇》 《C语言进阶篇》 ⛺️生活的理想,就是为了理想的生活!    🌈 hello! 各位宝子们大家好啊,今天给大家带来的是结构体的内存对齐这部分知识,可以说是干货满满啦!    ⛳️ 在我们C语言的面试题中,结构体最

    2024年02月16日
    浏览(39)
  • 编程语言如何推动DeFi成为主流?

    随着DeFi的快速增长,提供DeFi服务的平台和产品也如雨后春笋般纷纷冒头。作为衡量DeFi协议管理资金规模的标准之一,DeFi“总锁仓量”在过去两年一路从100亿美元增长到超400亿美元,期间更是一度冲上1800亿美元的巅峰。但直到今天,智能合约编程语言功能并没有足够完善到

    2024年02月01日
    浏览(43)
  • 实践tcpdump命令,成为网络数据抓包高手

    大家好,又见面了,我是沐风晓月,本文是专栏【linux基本功-基础命令实战】的第57篇文章。 专栏地址:[linux基本功-基础命令专栏] , 此专栏是沐风晓月对Linux常用命令的汇总,希望能够加深自己的印象,以及帮助到其他的小伙伴😉😉。 如果文章有什么需要改进的地方还请

    2024年02月03日
    浏览(28)
  • 一键收藏 | 最新学习干货,助你成为区块链高手

    新的一年已经开启,为了感谢大家的长久陪伴和倾力支持,我们将FISCO BCOS开源社区成立至今超400篇技术干货和经典篇章整理成文,作为区块链干货合辑,分享给大家! 干货合辑覆盖联盟链从入门到精通的各个阶段,既有应用案例也有技术教程分享更有社区伙伴和开发者积极共

    2024年01月16日
    浏览(30)
  • 并发编程——1.java内存图及相关内容

    这篇文章,我们来讲一下java的内存图及并发编程的预备内容。 首先,我们来看一下下面的这两段代码: 下面,我们给出上面这两段代码在运行时的内存结构图,如下图所示: 下面,我们来具体的讲解一下。 首先,我们写了一个java程序是以.java的文件形式保存在磁盘中的,

    2024年02月07日
    浏览(32)
  • 自学黑客(网络安全)必学内容

    随着时代的发展,经济、社会、生产、生活越来越依赖网络。而随着万物互联的物联网技术的兴起,线上线下已经打通,虚拟世界和现实世界的边界正变得模糊。这使得来自网络空间的攻击能够穿透虚拟世界的边界,直接影响现实世界的安全。 网络安全包括网络软件安全、网

    2024年02月05日
    浏览(30)
  • 开启JDK 11时代,掌握这些新特性,成为Java开发高手!

    大家好,我是小米,欢迎来到小米科技资讯公众号!今天我将为大家详细介绍 JDK 11 的一些新特性。JDK 11 是 Java 语言的一个重要版本,它带来了许多令人振奋的改进和功能,尤其是在电商应用领域。让我们一起来了解吧! JDK 11 引入了全新的 HTTP 客户端 API,取代了过时的 Ht

    2024年02月11日
    浏览(32)
  • 两分钟成为 ChatGPT 国内高手【不要再拿ChatGPT当百度用了】

    不要再问ChatGPT那些问百度的问题了,有 更进阶 的用法 更高效的编写prompts,以便ChatGPT 给出更精准的回答 但是需要注意的是: 国内现在根本没有GPT-4使用,但凡是说有GPT-4的都是骗子。 GPT 可以写文章,可以写诗,可以写总结,可以写小说,它也可以帮助你更好地完成工作。

    2024年02月02日
    浏览(33)
  • 我要成为嵌入式高手之2月19日Linux高编第四天!!

    练习1:利用read和write实现文件内容的拷贝(将src.jpg中的内容拷贝到dst.jpg文件中) 新知识点:主函数传参,在编译之后运行的时候将参数传入主函数 int main (int argc, const char *argv[ ])  参数:         argc:要传的参数个数         argv:要传的参数的首地址(char* 型)      

    2024年02月19日
    浏览(29)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包