运行-内存

一、内存

1.操作系统把磁盘上可执行文件加载到内存运行之前, 需要做很多工作, 其中很重要的一件事就是把可执行文件中的代码, 数据存放到内存 中合适的位置, 并分配和初始化程序运行过程中必须的堆栈, 所有准备工作完成之后操作系统才会调度程序起来运行.

2.进程在内存中布局主要分为4个区域: 代码区, 数据区, heap(堆)和stack(栈).

(1)代码区, 包括被CPU执行的机器代码(指令)和只读数据比如字符串常亮, 程序一旦加载完成代码区大小就不会再变化了. "代码"就是编 译器编译成机器代码的结果.
(2)数据区, 存放 全局变量静态变量, 常量
生成:与代码区一样, 程序加载完毕后数据区的大小也不会发生变化.
释放:程序结束之后自行释放
(3)堆, 程序运行时动态分配的内存位于 heap 中, 这部分内存由内存分配器负责管理. 该区域的大小会随着程序的运行而变化. 当我们向 heap 请求分配内存但分配器发现 heap 当中内存不足时, 它会向操作系统内核申请向高地址方向扩展堆的大小, 而当我们释放内存把它归还给堆时, 如果内存分配器发现剩余空闲内存太对则又会向操作系统请求向低地址方向收缩堆的大小.

堆区的数据由程序员管理操控和释放,最后由操作系统来回收。
eg. 使用new来开辟堆中的新内存; 指针本身在栈区,指针保存的数据在堆区。利用new创建的数据会返回相应数据类型的指针,释放操作符可以使用detel。

(4)函数调用栈——简称, 在程序运行过程中, 不管是函数执行还是函数调用, 栈都非常关键, 它的主要作用:
(存放局部变量和函数的参数)
保存函数的 局部变量;
向被调用函数 传递参数;
返回函数的返回值;
保存函数的返回地址. 返回地址是指从被调用函数返回后调用者应该继续执行的指令地址
编译器来开辟内存和自行释放。
注意:不可以返回局部变量的地址。

在这里插入图片描述

二、函数在内存中的调用机制与运行的过程

1.单文件(所以函数在main.c里)

首先执行main函数,在内存中开辟main栈,然后在main栈中存放在main函数中变量,当执行到fun1(a,b)这里时,程序又在内存中开辟fun1栈,然后在fun1栈中存放fun1函数中的变量,fun1函数执行完以后,立刻返回调用该函数的位置,然后fun1栈被销毁了,在内存中就没有了。

2.多文件中编程函数调用以及头文件的问题

首先建立一个c工程,这个工程包含:main.c、fun1.c、fun1.h、fun2.c、fun2.h、fun3.c、fun3.h。

头文件#include “fun1.h”//将这个头文件里边的内容复制一份过来替换到fun1.h这个位置,
调用机制与单文件一致。

三、 其他

(1) 声明

在单文件编程时,如果被调用函数定义在调用函数之前的话,那么就不用声明,如果被调用函数定义在调用函数之后的话,就需要在前边声明,否则编译器会报错误。那多文件编程时,函数定义在另一个.c文件中,如果其它.c文件要调用它时,就必须要声明,目的就是告诉编译器,我要调用它,你别报错啊,同样,编译器看到你声明了以后,就知道你在本文件或者其它.c文件中定义了该函数,就不会报错了。

(2) .h与.c

.h文件中一般只放函数声明、宏定义、变量声明,而函数的具体实现是定义在.c文件中的,名字相同就是.c文件用到的一些定义(除了函数)会定义在同名的.h文件中,更加方便维护。它俩名称可以不相同。

(3) 头文件

头文件中一般放置函数原型(声明)和宏定义,有时也可放置结构体声明、静态全局变量的定义。

(4) <>和""的区别:

<stdio.h>:尖括号包含文件,将告诉预处理器在 “编译器自带” 的头文件中搜索stdio.h;
“stdio.h”:双引号包含文件,将告诉预处理器在 “当前程序所在文件夹” 搜索stdio.h,如果没有,再去编译器自带头文件中搜索。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值