ICode9

精准搜索请尝试: 精确搜索
首页 > 系统相关> 文章详细

《C语言深度剖析》第五章 内存管理 p1(完结)( C语言从入门到入土(进阶篇)

2021-12-25 11:00:04  阅读:139  来源: 互联网

标签:释放 p1 程序员 free C语言 进阶篇 内存 空间 我们


目录

内存管理

1. 什么是动态内存

2. 为什么要有动态内存

3. 栈、堆和静态区

4. 

4.1. 常见的内存错误

4.1. 注意

4.2. 可以用memset来初始化

4.3. 内存泄漏如果程序退出了,问题还在吗?

4.4. 内存开辟实际上比我们预要开辟得多,为什么? 

4.5. 内存释放的本质上是什么?

5. C中动态内存“管理”体现在哪 


本章节文章是作者通过观看《C语言深度剖析》等各种资料总结的精华,基础部分省略了不少,是为了让大家能够更加深入了解C语言的魅力!因为为了避免与之前的文章发生赘述,所以就直接讲作者认为的精华部分哈!现在正文开始! 

 谁都不能阻挡你成为更优秀的人。 

内存管理

1. 什么是动态内存

就是开辟在堆上的内存,而且要用特定的函数去开辟,我们常用的是malloc,和free(释放空间)

返回一个内存块给用户,返回成功就是那块空间的起始地址,失败就是NULL。

free释放空间,参数就是之前获取返回值的指针变量。

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
#define N 10
int main()
{
        int *p = (int*)malloc(sizeof(int)*N); //动态开辟空间
        if (NULL == p){
        return 1;
        }
        for (int i = 0; i < N; i++){
        p[i] = i;
        }
        for (int i = 0; i < N; i++){
        printf("%d ", i);
        }
        printf("\n");
        free(p); //开辟完之后,要程序员自主释放
        system("pause");
        return 0;
}
 

2. 为什么要有动态内存

1. 在技术方面,普通的空间申请,都是在全局或者栈区,全局一般不太建议大量使用,而栈空间有限,那么如果一个应用需要大量的内存空间的时候,需要通过申请堆空间来支持基本业务。  
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <windows.h>
#define N 10
int main()
{
    char a[1024 * 1024]; //就简单的1M空间,程序就崩溃了
    system("pause");
    return 0;
}
2. 在应用方面,程序员很难一次预估好自己总共需要花费多大的空间。想想之前我们定义的所有数组,因为其语法约束,我们必须得明确"指出"空间大小.但是如果用动态内存申请(malloc),因为malloc是函数,而函数就可以传参,也就意味着,我们可以通过具体的情况,对需要的内存大小进行动态计算,进而在传参申请,提供了很大的灵活性

3. 栈、堆和静态区

 

我们发现地址从上到下依次增大,而且堆区(heap addr)和栈区差距巨大,也就是说中间有巨大的漏空(堆区向上增长,栈区向下增长)(也就是我们图中所看到的)。 

 

问一个问题:在C语言中,为何一个临时变量,使用static修饰之后,它的生命周期变成全局的了? 

编译的时候被编译进了全局数据区。(全局特性,但是注意作用域还是不变,只是生命周期是整个程序的生命周期) PS:栈区随着申请与释放而进行空间管理,而其他的区,基本上都是随着整个程序的运行而一直存在。

4. 

4.1. 常见的内存错误

1.指针没有指向一块合法的内存 2.为指针分配的内存太小 3.内存分配成功,但并未初始化 4.内存越界(越界是一个很严重的问题,但不是所有严重的问题都会表现出来 ) 5.内存泄漏

4.1. 注意

assert称为断言,如果内部条件不满足,就会报错,满足就什么都不做。但是一般用if,因为如果我们需要的情况是指针为NULL(默认行为)assert是解决不了的,而且assert一般只有在发布方式为 Debug下面有效,还有要是我们自己定义一个地址去指向非法行为,assert(if)也是没有办法去判断的,因为他也不知道用那个地址是不是非法的,所以我们写指针如果未直接引用,就要设置为NULL。 

4.2. 可以用memset来初始化

4.3. 内存泄漏如果程序退出了,问题还在吗?

答案是当一个程序开辟了很多空间但是没有去释放,发生内存泄漏,但是如果程序结束,操作系统会强制把开辟的内存回收,也就是释放内存,所以是不在了。(注意不是编译器回收哈,因为代码运行起来之后就和编译器没有关系了)

那问题又来了,那什么程序最怕内存泄漏,就是那些不会主动退出的程序或者说很少主动退出的程序。(一般常见的有:操作系统,杀毒软件,服务器程序)(我们把这种经常性得使用的程序称为常驻(内存)进程(程序))

4.4. 内存开辟实际上比我们预要开辟得多,为什么? 

我们可以发现,我们free的时候只知道起始地址,并没有说要释放多少字节 

这是执行free语句的结果

但是我们free的时候发现变红的远不止20个,也就是说释放的远不止20个空间,也就意味着曾经申请的空间一定比20个字节多(这个多(kookie)是个固定的值,但是看编译器等)。多出来的部分其实是记录这次申请的更详细信息(申请空间多大,申请时间等)。再多说一句,所以申请大空间比较好,因为kookie的比值就小,而刚好申请小空间我们用栈,所以刚好互补。 

4.5. 内存释放的本质上是什么?

我们发现释放前和释放后p的值没变。那此时还能访问堆空间吗?

答案是不能,为什么呢?

这里来一个例子,假设你心中有一个女朋友的变量空间,里面开始什么都没有,后来喜欢上了一个人,然后你们在一起了,她的名字就在我们的变量空间里面,但是后来因为某种原因,她不喜欢你了,分手了,这就相当于free,但是她的名字任然在我们之前的空间里面,但是我们不能再去找她玩了,因为我们现在没有关系了,这个free就相当于取消了我们之间的关系,再去找她,就相当于野指针访问了! 

那free会不会将p置为空?

其实是不会的我们发现,为什么呢?因为此时用p再访问已经就是非法访问了,此时对系统没有影响,影响的只是我们自己的程序(分手后走不出来,和前女友没有关系,伤害的是我们自己啊QAQ),所以系统并没有强制设定为空,但是我们自己并不想这样,因为可能会出错(可能走不出来),所以我们free之后常把他设置为NULL(封心封心)。

5. C中动态内存管理体现在哪 

在今天的学习中,我们有效学到的函数是malloc和free,能够进行有效的空间申请和释放了 那么,通常书中所说的内存“管理”体现在哪里呢?难道就是malloc和free? 内存管理的本质其实是:空间什么时候申请,申请多少,什么时候释放,释放多少的问题。 1. 场景:C的内存管理工作是由程序员决定的,而程序员什么时候申请,申请多少,什么时候释放,释放多少都是有场景决定的(比如上面的链表操作),而大部分书中,是讲具体操作,很少有场景,所以管理工作体现的并不直观。不过我们现在能理解即可。 2. 其他高级语言:像java这样的高级语言,语言本身自带了内存管理,所以程序员只管使用即可。换句话说,内存管理工作,程序员是不用关心的。但是C是较为底层的语言,它的内存管理工作是暴露给程序员的,从而给程序员提供了更多的灵活性,不过,管理工作也同时交给了程序员。 所以,因为上面的两点,C中内存章节,基本都叫做内存管理 在C中,程序员+场景=内存管理

今天的内容就到这里了哈!!!

要是认为作者有一点帮助你的话!

就来一个点赞加关注吧!!!当然订阅是更是求之不得!

最后的最后谢谢大家的观看!!!

你们的支持是作者写作的最大动力!!!

下期见哈!!!

标签:释放,p1,程序员,free,C语言,进阶篇,内存,空间,我们
来源: https://blog.csdn.net/weixin_62700590/article/details/122128354

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有