当前位置: 首页 > news >正文

C语言中的内存管理

开始陆续的发一下唐老师视频的笔记吧,顺便带一些正冲哥书的的内容。不能一下都发出来,因为内容发多了自己也受不了,而且发的都是学习视频时候的一些笔记,可能会有一些问题不是很清晰。

先说一下C语言中的内存管理。

1.动态内存分配

①原因:程序运行过程中,很有可能需要一些额外的内存空间。
②动态内存从哪里来,还给谁?
  这块是内存是系统专门预留出来的,给程序动态的分配和动态的归还的。
  当free函数的参数为空的时候,那么我们的free什么事都不做了。
  clloc和realloc的用法见截图:

动态内存是从堆上分配空间的,具体形式以int为例 int *a = (int*)malloc (5*(sizeof(int)))。

2.栈,堆,静态存储区
①没有栈就没有函数,就没有局部变量。函数是依赖于栈的存在而存在的。
  这个栈不是数据结构中的栈,是内存栈。
  后进先出的原则没有改变。
  每一个函数的调用在内存中都会产生活动记录,这个活动记录包括函数的参数和返回地址等等,所以可以说这个活动记录就是在栈上面建立的。


  按照老唐的话说,一个栈应该包含的有如下数据
  (1)返回地址(子函数ebp在返回ebp的时候应该指向的位置)
  (2)old ebp
  (3)数据(包含函数中的所有数据)(这也是子函数和子函数esp指向的位置)
  栈的增长方式:从栈底一直向上增长。


②因为栈的数据在函数执行结束之后就会被释放了,没有传递到函数的外部,所以产生了程序中的堆。
堆中申请的内存在程序主动释放前一直有效。堆空间就是为了动态内存分配而产生的。
堆空间必须要通过申请才可以得到。
堆管理的方法有很多。老唐讲的链表法很清晰。
③程序静态存储区
程序静态存储区在程序运行的时候就已经开辟出来了,同时在程序运行结束的时候释放。
静态程序区的大小在程序编译的时候就已经规定好了。
程序的静态存储区主要用于保存程序运行的全局变量和静态变量。

这三个存储区是程序中所用的绝大数区域。

 

3.程序的内存布局。
程序中除了栈,堆,静态存储区以外还有其他的存储区么?
可执行程序的布局:
(1)可执行程序的文件头:操作系统来读这个可执行程序的文件头,看一下这个文件头里的信息是不是系统想要的信息。
(2).text段,这里面保存的是主函数和子函数的运行内容。
(3).data段,这里面保存的是申请并且赋值的全局变量,以及申请并且赋值的静态变量。
(4).bss段,这里面保存的是申请但是没有赋值的全局变量,以及申请并没有赋值的静态变量。
通过上面的四个段,没有找到保存申请并且赋值的局部变量的地方也没有申请但是没有赋值的局部变量的地方。因为局部变量是保存在栈空间中的。

 程序文件的布局是程序可执行文件的布局,并不是程序执行过程中的布局,堆栈和静态存储区才是程序执行过程(进程)的布局。
text段、data段和bss段在程序运行的时候(进程)会被映射到进程空间中。

 栈和堆是要等到程序运行之后由操作系统进行分配的。

这里的栈可以理解成为一个弹性的东西,所以在程序运行的时候映射过来的段和随着栈的行为来行动。
 静态存储区在程序编译的时候就已经开始分配空间了,所以静态存储区在程序运行的时候依然可以对应一部分程序的可执行文件的空间。函数的地址对应的是程序text段中的某个地址。

 

 

4.野指针通常是因为指针变量保存的值不是一个合法内存地址造成的。
  在C中没有任何手段来判别一个指针是否是野指针。

①局部指针变量没有被初始化。

#include <stdio.h>

	struct student
	{
		char *name ;
		int no ;
	};
	int main()
	{
		struct student s; 
		//这个strcpy函数是把后面指针变量的内存内容赋给前面指针变量的内容。但是前面的指针变量指向的内存并不确定,所以造成了野指针。
		strcpy(s.name,"haha");
		s.no = 10;
		printf ("%s,%d",s.name,s.no);
	}

解决办法:

#include <stdio.h>
	#include <string.h>
	struct student
	{
		char *name  ;
		int no ;
	};
	int main()
	{
		struct student s; 
		s.name = (char*)malloc(sizeof(char)*20);
		strcpy(s.name,"haha");
		s.no = 10;
		printf ("%s,%d",s.name,s.no);
	}

上面程序少了一个free(s.name).

②指针释放后程序就归还了这片空间,既然归还了那么就不可以再使用这篇空间了。
     使用已经释放后的指针。
  例程:

#include <stdio.h>
	#include <string.h>
	#include <stdlib.h>

	int f(char*i)
	{
		printf ("%s\n",i);
		free (i);
	}
	int main()
	{
		char *p = (char*)malloc(sizeof(char)*5);

		strcpy(p, "qwertyui");

		f(p);
		printf ("%s\n",p);
	}

解决办法:

 #include <stdio.h>
	#include <string.h>
	#include <stdlib.h>

	int f(char*i)
	{
		printf ("%s\n",i);
		//free (i);
		return 0;
	}

	int main()
	{
		char *p = (char*)malloc(sizeof(char)*10);

		strcpy(p, "qwertyui");

		f(p);
		
		printf ("%s\n",p);

		free (p);

		return 0;
	}

③指针所指向的变量在指针之前被销毁。

5.内存操作中的经典错误
①非法内存操作
②内存分配成功但是并没有初始化

例程;

#include <stdio.h>
	int main()
	{
		char *p = (char *)malloc(10);
		printf(p);
		free (p);
		return 0;
	}

③数组越界
④内存泄露
⑤多次释放指针----谁申请谁释放。
⑥使用已经释放的内存。

6.老唐自己的交通规则
①使用malloc之后应该立刻判断返回值是否为空。可以杜绝操作0地址里面的内容,这个地址是为操作系统使用的。

例程:

#include<stdio.h>
	int main()
	{
		int *p = (int*)malloc(sizeof(int)*5);
		
		if (p !== NULL)
		{
			.....
		}
		free (p);
		return 0;
	}

②牢记数组长度,防止越界操作。----使用柔性数组。
③动态申请的操作必须和释放操作相匹配。
④free指针以后,被free的指针要赋值为空。

 

相关文章:

  • 瀑布模型中的纠结
  • php生成UUID
  • u-boot-2011.06在基于s3c2440开发板的移植之引导内核与加载根文件系统
  • 自动YUM安装
  • HP iLo2 试用序列号
  • Javascript疑问二:匿名函数
  • 我们应该怎样获得加薪
  • Digester学习笔记(三)转载
  • 【C语言】09条件编译
  • c# winform项目用到的部分知识点总结
  • Intellij IDEA 快捷键整理(TonyCody)
  • C optimization tutorial 翻译 C语言优化教程(一)
  • eclipse 的代码着色插件 --Eclipse Color Theme
  • CentOS上yum安装nginx+mysql+php+php-fastcgi
  • 精简操作系统Linux
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • ESLint简单操作
  • Java 内存分配及垃圾回收机制初探
  • java2019面试题北京
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • PHP 小技巧
  • SegmentFault 2015 Top Rank
  • Spring声明式事务管理之一:五大属性分析
  • Vue2.0 实现互斥
  • vue数据传递--我有特殊的实现技巧
  • XML已死 ?
  • 记录:CentOS7.2配置LNMP环境记录
  • 如何利用MongoDB打造TOP榜小程序
  • 算法---两个栈实现一个队列
  • $refs 、$nextTic、动态组件、name的使用
  • (C++)八皇后问题
  • (JSP)EL——优化登录界面,获取对象,获取数据
  • (MonoGame从入门到放弃-1) MonoGame环境搭建
  • (二)Eureka服务搭建,服务注册,服务发现
  • (翻译)terry crowley: 写给程序员
  • (附源码)springboot电竞专题网站 毕业设计 641314
  • (理论篇)httpmoudle和httphandler一览
  • (力扣)1314.矩阵区域和
  • (六)vue-router+UI组件库
  • (全注解开发)学习Spring-MVC的第三天
  • (四)TensorRT | 基于 GPU 端的 Python 推理
  • (转载)跟我一起学习VIM - The Life Changing Editor
  • ***检测工具之RKHunter AIDE
  • .net mvc actionresult 返回字符串_.NET架构师知识普及
  • .net mvc 获取url中controller和action
  • .NET/C# 中你可以在代码中写多个 Main 函数,然后按需要随时切换
  • .net的socket示例
  • .net开发引用程序集提示没有强名称的解决办法
  • .net利用SQLBulkCopy进行数据库之间的大批量数据传递
  • .NET学习全景图
  • @autowired注解作用_Spring Boot进阶教程——注解大全(建议收藏!)
  • @Query中countQuery的介绍
  • [ C++ ] STL_vector -- 迭代器失效问题
  • [2018/11/18] Java数据结构(2) 简单排序 冒泡排序 选择排序 插入排序
  • [BZOJ1053][HAOI2007]反素数ant