C语言笔记之存储类

在C语言中,一个数据对象(往往是指变量)可以由3种属性来描述:作用域,存储时期,链接。每种属性有不同的值,这些不同值的组合构成数据对象的存储模型,又称为存储类,即,一个数据对象如何存在于计算机中。以下描述中,我们以变量为例(另一个例子是函数)代表数据对象。

一、作用域

作用域属性描述了一个数据对象可以在(源代码的)哪些区域被访问,它有以下几个值:代码块、函数原型、文件。

1、文件作用域

函数是C源代码文件的基本组织单位,但是如果一个变量定义在所有函数之外,即没有在任何一个函数体内,那么该变量就具有文件作用域,其范围是从变量定义处直到文件结尾。在此范围内的任何一个地方都可以访问它。需要注意的是,C语言规定所有变量都必须先声明再使用,所有在定义变量之前的地方是不能访问该变量的。

2、函数原型作用域

首先应弄清楚什么是函数原型。有关函数的几个概念很容易混淆,它们是:函数原型、函数定义、函数声明。函数声明包括前两者,而函数原型和函数定义的区别在于有没有函数体,有就称为定义,没有就是原型。更本质的区别在于,函数定义是要分配存储空间的,而函数原型不必。

函数原型的作用域是从变量定义处直到原型声明的末尾,但是这个作用域似乎没啥用啊。。。

3、代码块作用域

代码块是指包含在一对花括号之间的区域,代码块作用域的范围也就是这对花括号之间。

void show(int i) {

int j;

if (i < 0) {

int k = 2;

i = i + k;

}

j = i * 3;

return j;

}

在这段代码中,k定义在if{}块中,所以在该块之外k是无法访问的,比如把j = i * 3;换成j = i * k;就是错的。

要注意的是,这段代码是一个函数定义,在定义中有形式参数i,它的作用域也是代码块,即show{}的函数体内,而不是函数原型中的那样。也许这就是为什么把函数原型作用域单独提出来的原因吧。。。

C99把代码块的概念扩大到for()  while() if()语句的圆括号,在圆括号内定义的变量也具有代码块作用域。

二、存储时期

该属性描述了一个变量的“存活时间”,它有两个值:静态存储时期和自动存储时期。前者在程序执行期间一直存在;后者在使用完毕之后就被系统自动清除,释放内存。

存储时期和作用域是相互关联的,不能随意组合。一般来说,具有文件作用域的变量都有静态存储时期;而代码块作用域变量具有自动存储时期。

三、链接

链接属性描述了一个变量是否可以被其他文件引用。一个C程序往往由多个C源文件组成,所以在一个文件中定义的变量如果可以在另一个文件中被引用会方便很多。但是也有一些变量是专门为本文件服务的,不希望被其他文件引用,否则会引起混乱。链接属性就是为解决这一问题设计的。

该属性有3个值:内部链接、外部链接和空链接。链接同样和作用域紧密相关,不能随意组合。一般来讲,具有文件作用域的变量可能具有内部链接或外部链接,而具有代码块作用域或函数原型作用域的变量只有空链接。具有外部连接的变量可以被其他文件使用;具有内部链接的变量只能在本文件内部使用;而具有空链接的变量只能在代码块或函数原型内使用。

四、组合

三种属性经过“有条件的”组合之后形成以下五种存储类:自动、寄存器、具有外链的静态、具有内链的静态、具有空链的静态。用下图说明它们的各个属性组合:

5种存储类按照作用域来划分为代码块和文件两大类,作用域确定了,其他的都好说。

存储时期的自动与静态可以分别用关键字auto和static来显式声明,而链接的内部或外部分别由static和extern来修饰。但是对于不同作用域的变量,存在着默认情况。

由上表可知,只要是作用域为代码块的变量,其存储时期默认为自动,从而auto都是省略不写的;但是要使这样的变量具有静态存储时期,就必须显式的使用static声明。链接类型的话,都是空链接,不再区别内外。也可以看到,这类变量都是定义在代码块内部的,抛开寄存器变量这个异类,这类变量之间的唯一区别就在于有没有被static修饰(从而意味着是不是静态变量)。

另一大类变量就是定义在所有函数之外的具有文件作用域的变量了,它们的存储时期只能是静态的,不可以被auto修饰;而链接类型默认为外链,于是extern一般都省略不写。要使之成为内链,则需使用static修饰。

可以总结一下static的作用:显然它对不同作用域的变量的作用是不同的,对代码块作用域的变量,它的作用是使之成为静态变量;而对于文件作用域的变量,它的作用是使之成为内链变量。

把变量划分这么细有啥用呢?比如,在文件开头定义了一个变量a,然后在函数内部又定义了一个同名变量,那么计算机会不会混淆呢?在函数内部到底谁在起作用呢?这时,存储类就派上用场了:不同的存储类变量会被存放在内存的不同区域,即使它们是重名的。在函数内部,内部定义的变量将覆盖外部变量,起作用的将是内部变量。

还有,就是两类变量的初始化方案不同:文件作用域变量如果没有初始化,系统会自动为其赋一个默认值,但是代码块作用域的变量享受不到这个待遇。

时间: 2024-10-05 22:06:03

C语言笔记之存储类的相关文章

C语言--存储类、链接和内存管理

注:此文为<C Primer Plus>一书中的部分总结,写下来方便以后参考. 用于存储程序数据的内存可用存储时期.作用域和链接来表征. 存储时期可以使静态的.自动的或者分配的.①如果是静态的,内存在程序开始执行时被分配,并行程序运行时一直存在.②如果是自动的,变量所用内存在程序执行到该变量定义所在代码块时开始分配,在退出代码块时释放.③如果是分配的内存,内存通过调用malloc()(或其他相关函数)分配,通过调用函数free()释放. 作用域决定哪一部分程序可以访问某个数据.在所有函数之外定

C++语言笔记系列之十七——虚基类

1.虚基类 考虑这样一种情况:当某个类的部分或者全部直接基类是另一个共同基类派生而来,这些直接基类从上一级基类继承而来的成员就一定拥有相同的名称,这样就会产生二义性问题. 解决办法:当派生类和直接基类产生了二义性问题-->加类的作用域. 当派生类和间接基类产生了二义性问题-->虚基类. 2.虚基类的说明: class 派生类名:virtual 访问权限 基类名 {派生类定义}; 注意:在定义派生类时将需要继承的基类进行虚化声明,虚基类的说明在派生类的定义中完成. 作用:将基类说明为虚基类之后,

C++语言笔记系列之十三——派生类构造函数的调用

1.派生类构造函数的调用 (1)一个基类的所有数据成员均被派生类继承.创建一个派生类对象时,系统在为派生类对象分配单元时一定要为其基类数据成员分配子空间. (2)一个派生类对象在创建时不仅要调用派生类构造函数,而且要调用基类构造函数. 派生类中的数据成员在派生类中构造. 基类中的数据成员在基类中构造. 原因: A.构造函数不继承. B.派生类的构造函数必须通过调用基类的构造函数完成基类数据成员的初始化. C.若派生类中含有子对象,必须调用子对象的构造函数. 2.派生类的构造函数 派生类名(总参数

4.7 C语言的存储类,作用域,生命周期,链接属性

C语言背后的运行机制,学会了会对C语言更加熟悉,可以直接看到C语言的骨头里去. 存储类(storage class): ①什么是存储类? 存储类就是变量存储类型,即变量在内存中存储在什么段. 例如:栈:普通局部变量. 数据段(.data):初始化不为零的全局变量,静态局部变量. bss段:初始化为零 或 未初始化的全局变量. (其实bss段就是初始化为0的数据段)   代码段(.text):存放程序执行代码的一块内存区域. ②存储类相关的关键字? auto static register ext

C语言之存储类的相关的关键字

不同的数据在内存中的存储位置是不同的,总体来说内存中存储数据的地方主要有四部分:栈.堆.数据段.bss段,这些地方分别存放着不同的数据,比如栈一般用来存储局部变量,堆内存需要程序员字自己申请以及释放,主要用来存放比较大的数据:数据段主要用来存放显示初始化的全局变量和static关键字修饰的静态局部变量:bss段一般用来存放未显式初始化的全局变量或显式初始化为0的全局变量(C语言中,默认全局变量初始化为0).C语言还提供了一些关键字来修饰变量,使其附有其他的属性,这些关键字主要有:auto.sta

C++语言笔记系列之十五——派生类、基类、子对象的构造和析构函数调用关系

例子 example 1 注:若一个基类同时派生出两个派生类,即两个派生类从同一个基类继承,那么系统将为每一个简历副本,每个派生类独立地使用自己的基类副本(比如基类中有属于自己类的静态变量等). #include <iostream.h> class Person { public: person() {cout<<"Construction of person."<<endl;} ~person() {cout<<"Destr

c语言中用户标识符的作用域和存储类(2)

2 局部变量及其作用域和生存期 2.1 auto变量 当在函数内部或复合语句内定义变量时,如果没有指定存储类,或使用auto说明符,系统默认所定义的变量为自动类别.因此: float a; 等价于 auto float a; auto变量的存储单元被分配在内存的动态存储区.当进入函数体时,系统自动为auto变量分配存储单元:退出时自动释放这些存储单元.这类局部变量的作用域是从定义的位置起,到函数体结束为止.由于函数的频繁调用,动态存储区内为某个变量分配的存储单元位置随程序的运行而改变,变量的初值

C语言学习系列(六)存储类

一.C存储类 存储类定义C程序中变量/函数的范围(可见性)和生命周期.这些说明符放置在他们所修饰的类型之前.for example:auto.register.static.extern. (一).auto存储类 auto存储类是所有局部变量的默认存储类. { int mount; auto int month; } 上面的实例定义了两个带有相同存储类的变量,auto 只能用在函数内,即 auto 只能修饰局部变量. (二).register存储类 register存储类用于定义存储在寄存器而不

C语言的存储类

Auto  普通局部栈变量:是自动存储,限定变量只能在函数内部使用,这种对象会自动创建和销毁 ,建议这个变量要放在堆栈上面,调用函数时分配内存,函数结束时释放内存.一般隐藏auto默认为自动存储类别.我们程序都变量大多是自动变量. 实例 auto.c 1 #include <stdio.h> 2 3 int main(void) 4 { 5 auto int i = 9; /* 声明局部变量的关键字是 auto; 因可以省略, 几乎没人使用 */ 6 printf("%d\n&quo