Huge Lemon的博客

C语言中变量存储类型和生存周期

2020-01-28

内容来自谭浩强的《C语言程序设计》总结

原文链接:https://blog.csdn.net/wuyuzun/article/details/82432355

几个重要概念

  1. 数据类型:浮点型,整型,字符型等都是一个数据类型;

  2. 数据存储类型:数据在内存中的存储方式;(这是本博文要讨论的重点)
    注意:数据类型和数据存储类型都是针对于声明或定义的函数和变量而言的;

  3. 动态存储类型:变量或函数,在被使用时临时分配内存单元,在函数结束后所占用的内存单元将会被释放,例如局部变量;因此,动态存储的变量每次被调用时所占的内存单元的地址可能会发生改变;

  4. 静态存储类型:变量或函数,在程序运行期间编译器统一分配内存单元,直到程序结束分配的内存才被释放;例如:全局变量;

内存中供用户使用的存储空间

用户区 存储内容
程序区 CPU指令
静态存储区 全部的全局变量,局部静态变量
动态存储区 被调用函数的形参;被调用函数中非局部静态变量;函数调用时的现场保护和返回地址等

注:

  1. 在平时编程过程中,一般对变量和函数的声明和定义都应同时指定数据类型和数据存储类型;如果我们没有对变量进行指定数据存储类型;
  2. 在定义全局变量和局部静态变量时,如果没有赋初始值,系统会默认为0;而动态变量们竟会被随机赋值;

局部变量的存储类型

1. 自动变量—auto

定义:函数中,包括复合语句内和形式参数在内的变量中,不被static限制的变量;

性质:动态存储类型,系统调用函数时临时分配内存单元;函数执行结束就占用的内存释放;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>

int fun1(int a);

void main()
{
for(int i=0;i<5;i++)
printf("%d\n",fun1(5));
}

int fun1(int a) //形式参数
{
auto int b = 0; //函数内不被static限制,且函数每次被调用,b的值都会被赋0;
b++;
{
int c; //函数内复合语句内;
}
return b;
}

运行结果:

注:大多数情况下,自动变量是可以直接省略auto的,系统也会默认为自动变量;

2. 静态局部变量—static

定义:函数内被静态static限制的局部变量;静态局部变量在函数执行结束时,内存不被释放,函数下次被执行的时候,此变量的值并不改变;

性质:静态存储类型,函数每次被调用其值还是上次函数执行时的值,且默认的初始化的值是$0$;

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

int fun1(int a);

void main()
{
for(int i=0;i<5;i++)
printf("%d\n",fun1(5));
}

int fun1(int a)
{
static int b=a; //第一次执行函数后被b被赋初值,
//以后再执行函数后b将不会再被赋值;
b--;
return b;
}

输出结果:

3. 寄存器变量—register变量

定义:存放在CPU寄存器中的变量;(寄存器存储类型也是随着函数的结束,内存被释放)

形式:register int a = 1; \将定义的a送到寄存器中;

说明:寄存器这个名词如果是学过单片机的同志肯定是知道的,对于单片机功能的实现,基本上都是靠配置寄存器实现的;寄存器是什么,参考《存储器》

性质:CPU能够快速读写寄存器变量;

优点:一般来说,程序中定义,声明的变量是放在内存中的,例如全局变量存储在静态存储器中,对一个全局变量的每次读写操作都是CPU和内存之间的传输;但是寄存器变量是把变量存储在CPU的寄存器中,由于寄存器的读写传输速度很快,所以非常适合处理一些程序中被高频使用的变量;

缺点:CPU寄存器数量有限,不适合定义太多寄存器变量;

注意:
目前计算器处理速度越来越快,加上C语言IDE对于代码的优化越来越好,所以有时即使我们不去定义或声明一个寄存器变量,IDE也会把高频使用的变量默认声明为寄存器变量;所以在平时的编程时,并不用过于强调寄存器变量。

全局变量的存储类型

外部变量:定义在函数外的变量,也可以说就是全局变量;

全局变量的有效域:自定义处起以下范围;

举例:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

void main() //全局变量a不被main()函数调用;
{
}

int a=10; //全局变量a

void fun1() //全局变量a可以被fun1()调用;
{

}

1. 同文件内扩展外部变量的作用域 — extern

举例:

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
extern int a;
void main() //全局变量a不被main()函数调用;
{
}
int a=10; //全局变量a

void fun1() //全局变量a可以被fun1()调用;
{
}

在第二行语句以下的函数都可以调用变量a;外部变量声明也可以写成:“extern a”这种形式,因为a已经是已经定义过的变量;
注意:extern并不是定义变量,而是声明变量,这个关键字就是为了告诉编译器:本文件中已经定义这个变量;

2. 将外部变量的作用域扩展到其他文件–extern

怎样扩展:一个大的程序往往是由许多源文件和头文件组成,当不同文件要引用同一个外部变量时,方法是:在任意一个文件中定义外部变量,而在另一个文件中用extern对其进行“外部变量声明”;这样,在编译连接时编译器好知道这个变量来自于其他位置;如果说两个文件同时用了定义了相同名字的外部变量,那编译器连接时会报错;

扩展的方式:当程序进行编译的时候,编译器遇到extern所声明的变量后,编译器会现在本文件中寻找此变量,如果找到了,就在此处扩展有效域,如果找不到,会进入其他文件进行寻找,找到后将有效域扩展其他文件,如果还找不到就按错误处理;

3. 静态外部(全局)变量–static

定义:定义在函数外部的静态变量;

优点:被static限制的外部变量,编译时不会被其他文件发现,即使不同文件之间有同名的现象也没关系;如果确定一个外部变量不被其他文件引用,就可以直接加static,这一点很符合C语言模块化的思想,也提高了程序的可移植性;

举例:

1
2
3
4
5
6
#include <stdio.h>

static int a; //静态全局变量,只能在本文件中被调用;如果在其他文件被调用将会报错;
void main()
{
}

所以:对于static来说,静态局部变量说明的是此变量的生存期;静态外部变量说明的是此变量的作用域

三个概念:

生存期:一个变量值在某一时刻是存在的,则这个时期就是这个变量的生存期;
作用域:一个变量在某个文件或函数范围内是有效的,则这个范围就是这个变量的作用域;
可见性:在一个变量的作用域可以引用该变量,则说这个变量在这个作用域是可见的,这么一个性质就是可见性;

总结

  1. 存储类型(即存储类型关键字)是数据在内存中的存储方式,有四种:autostaticexternregister

autoregister用于声明内部变量,auto变量存储在中;extern用于声明外部变量,static用于声明内部和外部变量,externstatic变量存储在静态存储区中。内部变量默认是auto类型,外部变量默认是extern类型。

  1. C语言中,常量存储在常量区,该区数据可读不可写。
    static全局变量和static局部变量都存储在全局数据区。

  2. C语言中,除了关键字,还有单词类型(语法符号):标识符、运算符、分隔符、常量、注释符。

Tags: C/C++
使用支付宝打赏
使用微信打赏

若你觉得我的文章对你有帮助,欢迎点击上方按钮对我打赏