变量类型
块变量
语句块(程序块):指使用大括号{}括起来的一组语句
在一个语句块内部的变量,叫做块变量
if(...)
{
int i; //块变量
...
}
(1)生命周期:从定义开始,一直到程序块结束
(2)作用域(访问范围): 在语句块内部
局部变量
在函数内部定义的变量叫做局部变量,局部如果没有进行初始化,那么这个变量是一个随机数
void fn(void)
{
int a;
}
(1)生命周期:从定义开始,一直到函数结束
(2)作用域:从定义开始之后的整个函数内部可以访问
静态局部变量 使用关键字static修饰的局部变量
void fn(void)
{
static int a;
}
(1)生命周期:整个程序
(2)作用域:和普通局部变量一样
(3)作用:一般可以用于计数,只要程序不结束,可以实现不停的累加
全局变量 (在全局变量前面加static 成为静态全局变量(表示只能在当前文件使用))
定义在整个程序内部的变量,一般都定义在程序的开头位置,或者头文件,全局变量会被自动初始化为0
(1)生命周期:定义开始,一直到整个程序结束
(2)作用域:定义开始,在整个程序内部都可以访问
不同范围的同名变量
如果全局变量、局部变量以及块变量同名,那么在块变量范围内,块变量优先,在局部变量范围内,局部变量优先,最后才轮到全局变量 -》 局部优先
程序在内存中区域划分:
操作系统对内存条进行以下分配,它把内存条分为了五个部分:
(1)程序段:用来存放程序的代码,程序段是只读的
(2)数据段:用来存放的已经初始化的全局变量和静态局部变量
(3)BSS段:用来存放没有进行初始化的全局变量,自动初始化为0
(4)堆区:用来进行动态内存的分配(malloc/calloc/realloc/free)
(5)栈区:操作系统自动进行内存的分配和回收,一般存放局部变量
例子:
//使用递归函数实现计算n的阶乘
#include <stdio.h>
//定义一个递归函数
Int p = 0;
int jiecheng(int num)
{
if(1 ==num)
{
StaticInt lv = 0;
return1;
}
returnnum*jiecheng(num-1);
}
int main()
{
int data= 0;
printf("请输入一个整数:\n");
scanf("%d",&data);
printf("%d的阶乘是%d\n",data,jiecheng(data));
return 0;
}
1、 在程序段中,保存了这个的源文件的内容
2、 数据段中,保存了全局变量和静态局部变量的内容(值与名称),即保存了 p= 0 和 lv = 0
3、 BSS 段 ,由于没有没有初始化的全局变量,则这个没有保存
4、堆区,是程序员手动申请内存时,系统分配的区域,释放的时候也是程序员手动释放一般使用(malloc/calloc/realloc/free)
5、栈区,没有使用(malloc/calloc/realloc)申请的内存,操作系统自动进行内存的分配和回收,一般存放局部变量 如上边 data = 0; num
详细分析:
程序第一步,先进行预处理,判断有没有语法的错误,并导入相应头文件中对应的源文件,第二步将代码编译成.o文件,第三步生成可执行文件
在运行可执行文件的时候开始分配内存,
第一:因为在main函数之前得先扫描全局变量,所以先分配的是p 的内存(在数据段中),并赋值为0,但是0是保存在只读常量区,还有字符,字符串都一样,所谓的赋值就是在只读常量区中复制一份数值然后赋予变量
第二:进入main函数了,在栈区分配data的内存,并赋值为0;
第三:调用printf函数,printf函数调用的时候,系统在内存条栈区分配(分配规则系统自定)函数执行所需空间(该大小是函数变量),之后屏幕打印 “请输入一个整数:\n”
第四:调用scanf函数,同上,不过该函数功能则是保存了用户输入的值,在通过&data,找到data地址,把值赋进去
第五:调用自定义函数,由于该函数为递归函数,但是递归过程调用的函数还是该函数,所以地址不变
注意:
register:寄存器
修饰的变量叫寄存器变量,告诉编译器,这个变量会频繁使用,请保存在寄存器中,因为读取寄存器中数据的速度比内存快
使用限制:
(1)必须能被CPU的寄存器接受
(2)不能对寄存器中的变量取地址
(3)有些系统并不会把这种变量放在寄存器中,主要取决于编译器
(4)还有的编译器会把很频繁使用的变量放在寄存器中,虽然他们没有被register修饰