C语言中的数据还可按照是否可以变化分为变量和常量。
本文涉及关键字const,static,extern
1、 常量
常量,顾名思义,就是常数,在程序运行期间不会变化,值不变。常量的声明使用关键字const。
如:
const int a = 1;
此语句将a声明为常量1,且a的值不能再改变。当对a再赋值则程序会提示错误。因此常量的赋值在声明时初始化,或者为函数的形参,表明调用始参的值在函数中保持不变。
语句中const位置可以与int调换,在对指针进行常量声明时,有一个地方需要注意一下。
如:
int const *p1;
int *const p2;
这两种声明方式,前者指针p1实际上所指地址可以改变,但所指地址的值不变,即其指向整型常量。后者指针p2所指地址不可变,但地址上的值可变。即p2才是真正的“指针常量”。当然也可以这样声明:int const *const p;则p是“指针常量”且指向整型常量。
常量的声明还可以用另一种方式实现。
如:
#define FIVE 5;
则FIVE表示常量5,define机制是一种替代的方式。程序在预编译时,判断define的声明,将程序代码中包含有define定义的名字替换成其后面带的表达式。如上,则在预编译时,程序代码中的FIVE先被解释成5,再进行编译。关于define还有许多用途,本文不细讲。
2、 变量
变量,即在程序运行中可以改变其值。声明方式为:
说明符(关键字)变量列表(变量的名称);
如:
inta;
intb,c;
前者声明了整型变量a,后者声明了整型变量b,c;声明多个变量时,以’,’分隔开。声明时的初始化需要注意:
inta,b = 1;
则只对b进行了初始化,如果要对a也初始化,则需要:
inta = 1, b = 1;
声明变量后可以用赋值操作来改变变量的值。针对变量,最需要在意的是变量的几种属性—作用域,连接属性和存储类型。
2.1、作用域
作用域,通俗一点就是变量的有效范围。当一个变量被声明时,只有在其作用域范围内才能访问该变量。作用域按照作为范围的不同主要分为—代码块作用域,文件作用域,函数原型作用域和函数原型作用域。还有一种比较少见的函数作用域,只适用于goto语句。
2.1.1、代码块作用域
代码块作用域,即作用范围为代码块。C语言中一对{}即为一个代码块。当然,一旦有’{‘,则必然有其对应的’}’,否则存在语法错误。代码块也可存在嵌套的关系。
如 :
{代码块1
{代码块2
}
代码块1}
一个变量在代码块内声明,则具有代码块作用域,表示该变量只在该代码块中可被访问。
如:
{ //代码块1
inta = 1;
{ //代码块2
intb = 2;
}
}
则a 的作用范围为代码块1,b的作用范围为代码块2。代码块1包含代码块2,因此代码块2亦算做1的部分,因此,a在代码块2中也可被访问。但代码块2种也可再声明一个与a同名的变量,当然,这样做之后,在代码块2中就不能访问代码块1种的a了。
当然,以程序的可读性来说,应当避免在嵌套的代码块中声明与上层代码块同名的变量。
2.1.2、文件作用域
文件作用域的范围最大,从声明处到源文件结尾都访问。一般声明方式为在代码块之外声明即可。
2.1.3、函数原型作用域
函数原型作用域即在函数中声明变量的作用域。在函数原型中声明的变量作用范围只在该函数中。
2.1.4、函数作用域
只适用于goto的语句标签。即函数中的语句标签名唯一。
2.2、链接属性
链接属性与作用域有关,也是关于作用范围的一个属性,主要与文件相关。分为:ternal(外部)、internal(内部)和none(空)。具有代码块作用域或函数原型作用域的变量有空链接属性,即该变量为相应代码块或函数原型私有。而具有外部链接的变量可以在多个文件中被使用。具有内部链接的变量只能在源文件中被使用。
相关关键字为extern和static。在声明时指明变量连接属性。具有文件作用域的变量默认为extern。当加上关键字static时,则改变其连接属性为内部链接。
如在一个文件1.c中:
int a = 1;
static int b= 2;
则在其他文件可访问a,但b只能在1.c中被访问。当在2.c要用到a时需要在2.c中声明 externint a;表明2.c文件中的a来自外部链接。如果在2.c中声明int a;则创建了一个与1.c中a同名的变量。
2.3、存储时期
变量的存储时期分为静态和自动。具有静态存储时期的变量在程序执行期间都存在。具有自动存储时期的变量,在程序进入定义这些变量的代码块中时,为其分配内存;退出该代码块时,分配的内存被释放。
具有文件作用域的变量具有静态存储时期。具有代码块作用域的变量默认为自动存储时期,可用static关键字将代码块作用域的变量声明为静态存储时期。
2.4、总结
根据作用域、链接和存储时期,C定义了五种存储类,如下表:
存储类 | 存储时期 | 作用域 | 链接 | 说明 |
自动 | 自动 | 代码块 | 空 | 代码块内声明的变量 |
寄存器 | 自动 | 代码块 | 空 | 代码块内,用关键字register |
具有外部链接的静态变量 | 静态 | 文件 | 外部 | 函数之外声明的变量,其他文件要使用的话需添加包含关键字extern的声明 |
具有内部链接的静态变量 | 静态 | 文件 | 内部 | 函数之外声明,用关键字static |
空连接的静态 | 静态 | 代码库 | 空 | 代码块内用static声明的变量 |