C语言中的函数-变量的存储方式和生存期-上-学习笔记-20

变量的存储方式

前面我们说过,变量根据位置的不同,分为不同的作用域。今天我们通过变量存在的时间来观察变量的存储方式

动态存储方式和静态存储方式

有的变量是在程序运行过程中一直存在,有的则是在调用其所在的函数时才临时分配存储单元,而在函数调用结束后,该存储单元就马上释放了,变量不存在了。综上,我们发现变量根据存在时间的不同,分为动态存储方式静态存储方式两种。
静态存储方式:是指程序在运行期间,由系统分配固定的存储空间
动态存储方式:是指程序运行期间根据需要进行动态的分配存储空间的方式。

不同存储区域下数据的存储和释放

在内存中,可以供用户使用的存储空间分为一下三种:

  1. 程序区
  2. 静态存储区
  3. 动态存储区 数据分别存放在静态存储区动态存储区。像全局变量,就全部存方在静态存储区,在程序开始执行的时候,就给全局变量分配存储区程序执行完再释放

在程序执行过程中,全局变量一直占用着固定的存储单元,并不是动态的进行分配和释放的。

动态存储区域,常见的有:

  1. 函数的形参。在调用这个函数时,给形参分配存储空间
  2. 函数中定义的,没有用 static 声明的自动变量(后面会写)
  3. 函数调用时的现场保护返回地址等。

上面这些数据,在函数调用开始时分配动态存储空间,在函数结束时释放这些空间。在程序的执行过程中,这种分配和释放动态进行的。

因为是动态进行的用完就释放,所以程序如果两次调用一个函数,那么函数中的变量地址可能是不同的。

总结

所以,如果一个程序包含若干函数,每个函数中的局部变量的生存期不等同于整个程序的执行周期。因为局部变量的生存期是随着函数被调用的开始和结束来进行分配和释放的

在 C 语言中,每一个变量和函数都有两个属性,数据类型数据的存储类别

数据类型:诸如浮点型字符型整型等等。
数据存储类别:动态存储、静态存储等等

你知道吗?
其实在定义和声明变量或者函数时,一般应同时指定其数据类型和存储类型,也可以采用默认方式指定。也就是如果用户不指定,系统会自动指定一种存储类型。

局部变量的存储类别

C 的存储类型包括4中,自动的(auto)、静态的(static)、寄存器的(register)、外部的(extern)。

存储类别声明的一般形式

存储类别 数据类型 变量名;

自动变量(auto 变量)

在函数的局部变量中,如果不专门声明为静态(static)存储类别,则都是动态的进行分配存储空间的,数据存储在动态存储区。

在函数中的形参、函数中定义的局部变量、函数中复合语句定义的局部变量,都属于此情况

在函数被调用时,系统会给这些变量分配存储空间,在函数调用结束后,会自动释放这些存储空间,因此这类局部变量称为自动变量。自动变量用关键字auto来进行存储类别的声明。

1
2
3
int test( int a){
auto int b,c=3; //定义 b 和 c 为自动变量
}

上面的 a 是形参,b 和 c 是自动变量,所以执行玩 test 函数后,系统会自动释放 a、b、c 三个变量。

自动变量是我们使用最多的,前面我们没有特别的声明变量为自动变量是因为,int aauto int a 其实是等价的,所以auto关键字可以省略

静态局部变量(static 局部变量)

有时候我们也会遇到这种情况,希望在函数的局部变量中,在函数调用结束后,变量值继续保留,也就是其占用的存储单元不要释放,在下一次调用该函数的时候,函数内的这个局部变量就是上次调用结束后的值,这就是静态局部变量

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>
int main(){
int test( int num);
//初始化了一个 test 函数
auto int i,a=2;
//自动整型变量 a,并初始化为2。
for (i=0;i<3;i++){
printf("%d\n",test(a));
// 输出 3次 test(a) 的值,看看有什么变化
}
return 0;
}

int test(int num){
auto int b=0;
//自动整型变量 b
static int c=2;
//静态整型变量 c
b=b+1;
c=c+1;
//给这些变量自身+1
return (num+b+c);
//将这三个变量的和返回,看看谁有变化
}

上面的例子中,我们定义了三个变量,一个在 main 函数中,一个在自定义函数中,还有一个是 static 静态变量。我们在 main 函数中让一个自定义函数执行3变,并且输出值。看看发生了什么变化。

输出结果是:
6
7
8
Program ended with exit code: 0

我们发现,在自定义函数 test 中,b 和 c 都执行了自身+1的操作,但是结果只有静态变量 c 保留了自身的值,并且输出了出来。

总结

根据上面的例子我们发现:

  1. 静态存储变量属于静态存储类别。在静态存储区内分配存储单元,在整个程序执行期间都不释放自动变量属于动态存储类别,在动态存储区分配存储单元,函数调用结束后释放
  2. 静态局部变量在编译是赋初值,即赋初始值只有一次。变量会保留上次调用函数结束时的值。而对动态局部变量来说,赋值不是随着编译进行的,而是在函数被调用的时候才会赋值,并且每调用一次就重新赋值一次。
  3. 如果编译时,静态局部变量没有赋值的话,那么编译时则会自动获取一个静态局部变量初值0,如果是字符变量则是\0。如果是自动变量的话,它的初值不确定。因为调用时才会分配存储单元,没分配时,变量值不确定。
  4. 静态局部变量只是变量存在的时间改变了,并不改变变量作用域,因为是局部变量,所以只在该函数内才能调用

静态局部变量虽然方便,但是会影响程序的可读性,多次运行后弄不清变量当前的值是什么,所以不是必要的情况下,不要使用。

尾巴

这是我的个人学习笔记,主要是应付考研复习使用,充斥着一些吐槽和个人观点,并不严谨,欢迎大家参考、指正。


-------------The End-------------
欢迎请我喝咖啡哦~!