c提供了多种不同模型或存储类别在内存中存储数据。
作用域:
作用域描述程序中可访问标识符的区域。
作用域描述了程序中可以访问一个标识符的一个或多个区域。即变量的可见性。
一个变量的作用域可以是代码块作用域,函数作用域,函数原型作用域和文件作用域。
函数作用域:标识符在整个函数中都有效。仅用于goto语句的标签,这意味着即使一个标签首次出现在函数的内层块中,它的作用域也会延伸至整个函数。
#include
int n=0;
int main(void) {
printf("input a string: ");
loop: if (getchar()!='\n')
{
n++;
goto loop;
}
printf("output: %d\n",n);
}
块作用域:
块是用{ }括起来的区域。
标识符位于{ }中具有块作用域,从它声明的位置开始到右 } 括号之间有效。函数定义中的形参也算块作用域的,从声明的位置开始到函数末尾之间有效。
//声明在内存块中的变量,其作用域仅限于该声明所在的块;
double blocky(double c) //cleo块作用域开始;
{
double part = 0;
int i;
for(i=0;i<10;i++)
{
double q=c*i; //q的作用域开始;
...
part*=q; //q的作用域结束;
}
return 0; //cleo块作用域结束;
}
函数原型作用域:标识符出现在函数原型中,这个函数原型只是一个声明而不是定义(没有函数体),那么标识符从声明的位置开始到在这个原型末尾之间有效。例如void add(int num);中的num。
文件作用域:变量的定义在函数外面,具有文件定义域。标识符从它声明的位置开始直到这个程序文件的末尾都有效。这里,变量units具有文件作用域。
#include
int units=0;
void num(void);
int main(void)
{
...
}
void num(void)
{
...
}
一个C语言变量具有下列链接之一:外部链接(external linkage),内部链接(internal linkage)或空链接(no linkage)。
空链接:具有代码块作用域或者函数原型作用域的变量就具有空链接,这意味着他们是由其定义所在的代码块或函数原型所私有。
内部链接:具有文件作用域的变量可能有内部或外部链接,一个具有文件作用域的变量前使用了static标识符标识时,即为具有内部链接的变量。一个具有内部链接的变量可以在一个文件的任何地方使用。
外部链接:一个具有文件作用域的变量默认是具有外部链接的。但当起前面用static标识后即转变为内部链接。一个具有外部链接的链接的变量可以在一个多文件程序的任何地方使用。
static int a;//(在所有函数外定义)内部链接变量
int num; //(在所有函数外定义) 外部链接变量
int main()
{
int b;//空链接,仅为main函数私有。
...
}
该文件和同一程序其他文件都可以使用num,而变量a属于文件私有,该文件的任意函数都可以使用它;
一个C语言变量有以下存储期之一;
静态存储期 ,自动存储期,动态分配存储期和线程存储期。
静态存储期:如果一个变量具有静态存储时期,他在程序执行期间将一直存在。文件作用域变量具有静态存储期。注意:对于具有文件作用域的变量,关键词static表明链接类型,而不是存储时期。一个使用了static声明了的文件作用域的变量具有内部链接,而所有的文件作用域变量,无论他具有内部链接,是具有外部链接,都具有静态存储期。
块作用域变量也能存有静态存储期:如下ct存储在静态内存中,它从程序被载入到程序结束期间都将存在;
void more(int number)
{
int index;
static int ct=0;
...
return 0;
}
自动存储期:具有代码块作用域的变量一般情况下具有自动存储时期。在程序进入定义这些变量的代码块时,将为这些变量分配内存,当退出这个代码块时,分配的内存将被释放。这种做法相当于把自动变量占用的内存视为一个可重复使用的工作区或暂存区。
目前局部变量都是自动存储;
如下,number和index每次在调用num函数时创建,在离开函数时销毁;
void num(int number)
{
int index;
for (index = 0; index < number; index++)
printf("%d",index);
return 0;
}
线程存储期:用于并发程序设计,程序执行可被分为多个线程。具有线程存储期的对象,从被声明时到线程结束一直存在。以关键字_Thread_local声 明一个对象时,每个线程都获得该变量的私有备份。
动态分配存储期:使用函数:malloc()、free()在申请的内存未释放前一直存在;
存储类别 | 存储期 | 作用域 | 链接 | 声明方式 |
自动 | 自动 | 块 | 无 | 块内 |
寄存器 | 自动 | 块 | 无 | 块内,使用关键字register |
静态外部链接 | 静态 | 文件 | 外部 | 所有函数外 |
静态内部链接 | 静态 |
文件 | 内部 | 所有函数外,使用关键字static |
静态无链接 | 静态 | 块 | 无 | 块内,使用关键字static |
属于自动存储类别的变量具有自动存储期,块作用域。默认情况下,声明在块或函数头中的任何变量都属于自动存储类别。
自动变量指的是局部作用域变量,具体来说即是进入变量作用域时系统自动为其分配存储空间,并在离开做用域时释放空间的一类变量。在许多程序中,自动变量与局部变量所指的变量实际上是同一种变量,所以通常情况下“自动变量”与“局部变量”是同义的。
变量通常存储在CPU寄存器中。与普通变量相比,访问和处理这些变量速度更快。但由于寄存器变量存储在寄存器中而非内存中,所以无法获取寄存器变量地址,不能使用取地址运算符"&"求寄存器变量的地址。绝大方面,寄存器变量和自动变量一致。使用存储类别说明符register便可声明寄存器变量;
int main()
{
register int quick;
注意:寄存器与机器硬件密切相关,不同类型的计算机,寄存器的数目是不一样的,通常为2到3个,对于在一个函数中说明的多于2到3个的寄存器变量,C编译程序会自动地将寄存器变量变为自动变量。由于受硬件寄存器长度的限制,所以寄存器变量只能是char、int或指针型。
寄存器变量主要用于循环;
int main()
{
register int temp, i;
for ( i=0; i<=30000; i++ )
{
for ( temp=0; temp<=100; temp++ )
{
printf ("ok\n");
}
}
}
int main( )
{
int temp, i;
for ( i=0; i<=30000; i++ )
{
for ( temp=0; temp<=100; temp++ ) ;
{
printf ("ok\n");
}
}
}
第一个程序快于第二个。
所有全局变量都是静态变量,而局部变量只有加上static才是局部静态变量,局部变量可以在任何地方申请,申请成功后,将不再接受其他的同样的申请。
以下是一个内部(函数内部)静态变量的程序:
#include
void num(void);
int main()
{
int count;
for(count=1;count<=3;count++)
{
printf("Count is %d\n",count);
num();
}
system("pause");
return 0;
}
void num(void)
{
int fade=1;
static int stay =1;
printf("fade=%d and stay=%d\n",fade++,stay++);
}
不能在函数形参中使用static
int work(static int num) //不被允许
外部和静态变量都只会被初始化一次,而自动变量和寄存器变量每次进入函数都会被重新初始化一次。
外部链接的静态变量具有文件作用域,外部链接和静态存储期;该类别有时称作外部存储类别;属于该类别变量称为外部变量,把变量的定义声明放在所有函数外面便创建了一个外部变量,为了指出使用了外部变量,可以在该函数中用关键字extern再次声明。如果一个源代码文件使用的外部变量定义定义在另一个文件中,必须使用‘extern’在该文件中声明该变量。
int Errupt;//外部定义的变量;
double UP[100];//外部定义的数组;
extern char coal;//如果coal被定义在另一个文件中;
void next(void);
int main()
{
extern int Errupt;
extern double UP[100];
...
}
void next(void)
{
...
}
感谢观看!!
如果有哪里不对,还请指正。