一、作用域
1.1 块作用域
定义在块内的变量具有块作用域,块是用一对花括号括起来的代码区域。
1.2 函数作用域
函数作用域仅用于 goto 语句的标签。
1.3 函数原型作用域
函数原型作用域的范围是从形参定义到原型声明结束。这意味着,编译器在处理函数原型中的形参时只关心它的类型,二形参名通常无关紧要。而且,即使有形参名,也不必与函数定义中的形参名匹配。只有在变长数组中,形参名才有用。如:void use_a_VLA (int n, int m, ar[n] [m])
1.4 文件作用域
变量的定义在函数的外面,具有文件作用域。 这样的变量可用于多个函数,所以又称为全局变量。
1.5 翻译单元
C 预处理器实际上是用包含的头文件内容替换 #include 指令。所以,编译器源代码和所有的头文件都看成是一个包含信息的单独文件,这个文件被称为翻译单元。
二、链接
2.1 无链接
具有块作用域、函数作用域或函数原型作用域的变量都是无链接变量。
2.2 链接
具有文件作用域的变量可以是外部链接或内部链接。
2.2.1 内部链接
内部链接变量只能在一个翻译单元中使用,内部链接的文件作用域又称为 “文件作用域”。
2.2.2 外部链接
外部链接变量可以在多个文件中使用,外部链接的文件作用域又称为 ”全局作用域“ 或 ”程序作用域“。
三、存储期
3.1 自动存储期
**块作用域的变量通常都具有自动存储期。**当程序进入定义这些变量的块时,为这些变量分配内存,当退出这个块时,释放刚才为变量分配的内存。
3.2 静态存储期
文件作用域变量具有静态存储期。
注:static 关键字表明了其链接属性,而非存储期。有 static 关键字的是内部链接。
3.3 线程存储期
具有线程存储期的对象,从被声明到线程结束一直存在。
3.4 动态分配存储期
使用内存分配函数分配的变量。
四、存储类别
4.1 概述
存储类别 | 存储期 | 作用域 | 链接 | 声明方式 |
---|---|---|---|---|
自动 | 自动 | 块 | 无 | 块内 |
寄存器 | 自动 | 块 | 无 | 块内、使用关键字 register |
静态外部链接 | 静态 | 文件 | 外部 | 所有函数外 |
静态内部链接 | 静态 | 文件 | 内部 | 所有函数外,使用关键字 static |
静态无链接 | 静态 | 块 | 无 | 快内,使用关键字 static |
4.2 特性
4.2.1 寄存器变量
寄存器变量与自动变量相比,它存储在了最快的可用内存中。由于寄存器变量存在了寄存器而非内存中, 所以无法获取寄存器变量的地址。
可声明为 register 的变量类型有限,因为寄存器可能没有足够大的空间来存储 64 位的变量。
4.2.2 静态变量
静态变量是指在内存中原地不动,而不是它的值不变。
静态变量有块静态变量、外部链接的静态变量、内部链接的静态变量。
例:
#include <stdio.h>
int staticdemo(void);
int main(void)
{
int i;
for(i = 0; i < 10; i++)
printf("%d ", staticdemo()); //调用声明静态变量的函数
/*运行结果
1 2 3 4 5 6 7 8 9 10
*/
return 0;
}
int staticdemo(void)
{
static int demo = 0; //声明静态变量
return ++demo;
}
分析结果:
在第一次调用函数 staticdemo() 时声明静态变量并初始化为 0,之后再调用该函数,就不会对 demo 进行初始化,因为可以直接使用那个内存位置的量。
4.2.3 外部链接的静态变量
如果一个源代码文件使用的外部变量定义在另一个源代码文件中,则必须使用 extern 再该文件中声明该变量。
/*file1.c*/
int exVal = 100;
int exVal2 = 200;
/*file2.c*/
#include <stdio.h>
#include "file1.c"
int main(void)
{
extern int exVal;
int exVal2 = 50
printf("exVal = %d \n", exVal);
printf("exVal2 = %d \n", exVal2);
return 0;
}
/*运行结果
exVal = 100
exVal2 = 50
*/
分析结果:
exVal 使用了 extern 关键字,所以输出是 file1.c 中定义的值,而 exVal2 并未使用 extern 关键字, 所以是 输出的是 file2.c 中定义的值。
第一次声明称为定义式声明,第二次声明称为引用式声明,只有定义式声明才能初始化变量。
4.2.4 内部连接的静态变量
普通的外部变量可用于统一程序中的任意文件的函数,但内部链接的静态变量只能用于同一个文件中的函数。
例:
#include <stdio.h>
static int a = 100;
int main(void)
{
printf("static val a = %d \n", a);
return 0;
}
/*输出结果
static val a = 100
*/
4.2.5 动态存储变量
C可以在程序运行时分配更多的内存(如变长数组),我们也可以使用 malloc() 函数分配内存。malloc() 返回动态分配内存块的首字节地址。因此,可以把该地址赋给一个指针,并使用指针访问这块内存。因为 char 表示一字节,malloc() 的返回类型通常被定义为指向 char 的指针,然后使用强制类型转换转成想要的类型。
例:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i = 0;
double * ptd = (double *) malloc(5 * sizeof(double)); //声明 5 个空间的double数组
int * pti = (int *) malloc(3 * sizeof(int)); //声明 10 个长度的int数组
printf("enter 5 num to assign double arry: \n");
while (i < 5 && scanf_s("%lf", &ptd[i]) == 1) //获取 double 输入
i++;
printf("here are double arry: \n");
for (i = 0; i < 5; i++) //输出
printf("%7.2f", ptd[i]);
printf("\n");
free(ptd);
i = 0;
printf("enter 3 num to assign int arry: \n");
while (i < 3 && scanf_s("%d", &pti[i]) == 1) //获取 int 输入
i++;
printf("here are int arry: \n");
for (i = 0; i < 3; i++) //输出
printf("%d ", pti[i]);
free(pti);
return 0;
}
/*运行结果
enter 5 num to assign double arry:
9 10 4.4 8.9 10
here are double arry:
9.00 10.00 4.40 8.90 10.00
enter 3 num to assign int arry:
4 9 10
here are int arry:
4 9 10
*/
参考书籍
C Primer Plus (第六版)中文版