C语言既然可以自动为变量分配内存,为什么还要用动态分配内存呢?_类型已经定了为什么还要动态分配内存

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注go)
img

正文

图片如果想要弄清楚这些问题,我们首先就要了解静态内存和动态内存有什么区别,只有了解了他们两个的区别我们才能弄懂(理解)为什么需要动态分配内存!

今天的文章会用到以下知识点,大家可以作为了解内容去学习:静态内存、动态内存、堆、栈、全局变量、指针等。

既然要学习内存的相关知识,那我们就先从计算机的内存开始本篇的讲解吧!在计算机内存一共可以分为五个区域,其中有个区域是用来存储代码的,我们就不再进行讨论了。我们首先对这四个区域进行一个简单的了解,方便我们后面对于内存分配的理解。

我们首先看一张内存的组成图:图片从上面的图我们可以看出内存区域大概可以分为五个部分:堆、栈、全局/静态存储区和常量存储区、文字常量区。下面我们对这几个名词进行一下简单的讲解,心里先有个概念。

栈: 栈又叫堆栈,该区域是由编译器自动分配自动回收的变量的存储区。通常是用来存储局部变量的值、函数参数值等,是向下增长的。所谓向下生长的就是,先调用的栈帧的地址比后调用的地址大,栈一般大小有几个M左右。

堆: 就是那些由程序员通过malloc函数申请到的内存块,一般我们申请的内存空间系统是不会帮我们释放的(当然有些也会由系统释放掉),由我们的应用程序去控制,一般一个malloc就要对应一个delete/free,由程序员主动释放。

全局区(静态区): 全局变量和静态变量都存储在这块区域,与其余变量的明显区别就是生命周期不一样,在程序结束时,系统会释放掉。

文字常量区 : 这个区域主要用来储存一些我们定义的常量,例如下面的定义就会被存储在文字常量区:char* p = "hello word!";。该部分也是由系统控制,程序结束后由系统释放掉。

代码区: 该区域主要用来存放程序代码,程序结束后由系统释放。

通过上面的基本概念我们已经知道了内存中的几个区域,以及哪些区域是我们程序员可以手动释放的,哪些区域是由系统为我们自动释放的。

我们今天主要需要用到的是,因为我们今天要讨论的动态内存和静态内存和堆栈是密切相关的。动态内存是指在堆上分配的内存,而静态内存是指在栈上分配的内存。 这里也给大家贴出一张网上的图片,便于大家理解上面的知识。

了解完堆栈之后我们还有个知识需要了解就是指针,由于我对于指针的理解还不是特别透彻,所以有哪些说的不对的地方大家可以在评论区指出来,我会即时进行修改。

明明我们今天要讨论的是动态内存和静态内存,为什么要了解指针呢?如果你有这样的疑问说明你对于内存或者指针的理解还不是特别到位。指针和内存的联系非常紧密,没有内存指针也将失去意义,我们对指针进行的操作实际上就是在间接的操作内存。但是,大家需要注意指针也是有类型的,他的数据类型取决于它所指向的内存空间的数据类型。关于指针和内存的关系我们后面会进行详细的讲解。

有了上面基础知识的加持,我们现在就可以回归我们今天的主题来讨论为什么我们需要动态内存了!我这里先说一下我的理解,我对这个问题的答案总结出以下几点,当然这绝不是全部的原因,鄙人也是能力有限,只能理解到这种程度,更多的理解欢迎大家在评论区进行讨论!

  1. 节省资源:用多少申请多少,不需要了及时进行释放,这样可以避免资源的浪费。
  2. 方便储存大型对象:大家需要注意栈区不是无限大的,对于大型项目如果说有的变量都储存在栈区,很可能会造成栈区内存不够用。
  3. 方便对象的调用 :对于较大的对象我们使用动态内存存储时我们只需要通过指针将变量首地址传递出去即可,而不用将整个对象都进行传递。

对于上面说的三点我可以给大家举个简单的例子,方便大家理解:

对于第一点大家应该很好理解,我用多少就申请多少,节省资源,但是后面两点可能就不是很好理解了,这里给大家举个简单的例子:

你是一个开超市的,栈区就相当于你的超市,但是你会发现如果你如果把商品都放到超市,可能你的超市会装不下那么多货物。于是仓库就出现了,堆区就相当于你的仓库。这些仓库和你的超市是分离的,如果你发现你进了一些商品,这些商品短时间内也不会被完全卖出去,那你就可以把这些货物放到你的仓库里,而你只需要记住你仓库的地址即可。

这样就可以保证你的超市不会因为堆积太多商品而显得拥挤,如果有人要买这些商品,你可以把仓库地址告诉他,他就会直接去你仓库拿货。

听过这个故事你可能更迷糊了,我下面给你梳理一下,相信你会豁然开朗!

动态申请空间,能动态确定对象所需要的内存。

我需要多大的空间,就用多大的仓库存放该商品。

对于大型对象的存储,栈区容不下。

我有大量的商品,都放超市太占地方。可以放仓库中,记住仓库地址就行。

传递指针比传递整个对象更高效。

别人要买该商品,告诉别人我仓库地址,不用把整个仓库搬过去。

(感觉这个故事我还是没有讲好,表达能力欠佳)

知道了动态分配内存的好处后我们就可以更好的理解我们为什么要使用动态分配内存以及何时应该使用动态分配了,所以如果你进了几包方便面(建了个很小的对象)那你就没必要把方便面放到仓库了,直接放到超市货架上就可以了。

如果你超市比较小(代码量比较小)那你也没必要把东西放到仓库了,直接放到柜台上就可以了。所以很多问出为什么要使用动态分配内存的主要原因是因为他现在还没接触过大型项目,或者特别大的对象,如果你做过底层驱动开发或者上位机开发的话相信你对于动态申请内存并不会陌生的。

通过上面的故事我们大概也已经知道什么时候我们需要使用动态分配内存了,这里再简单的给大家做一个总结。

1、当你的代码量很大,需要用到很大的数据块来存储对象时。2、当你的程序中用到大数组时,你就需要用动态分配内存。3、需要数组长度根据程序进行变化。4、想让一个变量储存的内容不会因为函数的结束而被收回(有点像全局变量)

这里就不得不来讨论一下“传统数组”的缺点了,传统数组”就是前面所使用的数组,与动态内存分配相比,传统数组主要有以下几个缺点:

  1. 数组的长度必须事先指定,而且只能是常量,不能是变量。比如像下面这么写就是对的:
int a[5];
而像下面这么写就是错的:
int length = 5;
int a[length];  //错误

  1. 因为数组长度只能是常量,所以它的长度不能在函数运行的过程当中动态地扩充和缩小。
  2. 对于数组所占内存空间程序员无法手动编程释放,只能在函数运行结束后由系统自动释放,所以在一个函数中定义的数组只能在该函数运行期间被其他函数使用。

而动态内存就不存在这个问题,因为动态内存是由程序员手动编程释的,所以想什么时候释放就什么时候释放。只要程序员不手动编程释放,就算函数运行结束,动态分配的内存空间也不会被释放,其他函数仍可继续使用它。除非是整个程序运行结束,这时系统为该程序分配的所有内存空间都会被释放。

所谓“传统数组”的问题,实际上就是静态内存的问题。我们讲传统数组的缺陷实际上就是以传统数组为例讲静态内存的缺陷。本质上讲的是以前所有的内存分配的缺陷。正因为它有这么多缺陷,所以动态内存就变得很重要。动态数组能很好地解决传统数组的这几个缺陷。

知道了我们为什么要动态分配内存之后我们一起来学习以下C语言中如何进行动态分配内存。在C语言中动态分配内存使用的是函数malloc进行分配的。

malloc 是一个系统函数,它是 memory allocate 的缩写。其中memory内存的意思,allocate分配的意思。顾名思义 malloc 函数的功能就是分配内存。要调用它必须要包含头文件 <stdlib.h>,它的原型为:

# include <stdlib.h>
void *malloc(unsigned long size);

由上面的函数原型我们可以看出malloc 函数只需要一个形参,并且该形参是整形的。函数返回值为一个指向所分配的连续空间的首地址的指针。当函数未能成功分配存储空间时(如内存不足)则返回一个NULL指针。所以malloc 函数的返回值为一个指针。

由于堆区内存也是有限的,不能无限制地分配下去,所以秉持着尽量节省资源,我们应该在分配的内存区域不用时,及时释放它,以便其他的变量或程序使用。

释放malloc 函数分配内存的函数是free函数,free函数和malloc 总是成对出现的。free函数的原型如下所示:

# include <stdlib.h>
void free(void *p);



**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)**
![img](https://img-blog.csdnimg.cn/img_convert/57695d0ba54baa976810727c07740cc3.jpeg)

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
的朋友,可以添加V获取:vip1024b (备注Go)**
[外链图片转存中...(img-ySRiv3pV-1713709800455)]

**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
  • 55
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值