第9章c语言与程序设计补遗

上传人:今*** 文档编号:107035930 上传时间:2019-10-17 格式:PPT 页数:132 大小:645KB
返回 下载 相关 举报
第9章c语言与程序设计补遗_第1页
第1页 / 共132页
第9章c语言与程序设计补遗_第2页
第2页 / 共132页
第9章c语言与程序设计补遗_第3页
第3页 / 共132页
第9章c语言与程序设计补遗_第4页
第4页 / 共132页
第9章c语言与程序设计补遗_第5页
第5页 / 共132页
点击查看更多>>
资源描述

《第9章c语言与程序设计补遗》由会员分享,可在线阅读,更多相关《第9章c语言与程序设计补遗(132页珍藏版)》请在金锄头文库上搜索。

1、第9章 C语言与程序设计补遗,9.1 变量的存储类别与生命期 9.2 指向函数的指针变量 9.3 带参数的主函数main 9.4 编译预处理命令 9.5 枚举类型 9.6 位运算,9.1 变量的存储类别与生命期,1. 生命期的概念 从变量生命期(即由创建到撤消)来分,可以将变量分为静态存储变量和动态存储变量两类: (1) 静态存储变量:在程序运行时固定分配存储空间的变量。 (2) 动态存储变量:在程序运行中根据需要动态分配存储空间的变量。 程序运行时对应的内存分配示意如图9-1所示。,图9-1 程序运行时对应的内存分配示意,全局变量和静态局部变量(static变量)存放在静态数据区,程序开始执

2、行时给它们分配内存单元,程序执行结束时再释放这些内存单元。也即在程序的整个执行过程中这些变量都存在(有自己的内存单元),它们的生命期为程序的整个执行过程。,动态数据区存放自动局部变量、形参变量和用于中断现场的保护数据。自动局部变量是指未加staic声明的局部变量;形参变量是指函数的形参。在函数调用时为自动局部变量和形参变量在动态数据区分配内存单元,当函数执行结束时释放这些内存单元。也即在函数的整个执行过程中这些变量都存在,它们的生命期为函数的整个执行过程。 在C语言中,每个变量都有两个属性:数据类型和数据的存储类别。前面各章节中,我们在定义变量时只涉及它的数据类型,其实还可以定义变量的存储类别

3、,它决定这个变量的存放位置(是静态数据区还是动态数据区)和生命期。,变量定义的一般形式如下: 存储类别 类型标识符 变量名; 其中,方括号“ ”中的内容为可选项。 C语言中的变量可以有4种存储类别:自动变量、寄存器变量、静态变量和外部变量,分别用存储类别auto、register、static和extern。下面仅对自动变量、寄存器变量和静态变量进行介绍。,2. 自动变量 在函数体内或复合语句内定义变量时,如果没有指定存储类别或使用了“auto”存储类别,则系统都认为所定义的变量为自动局部变量,简称为自动变量。此外,函数首部中的形参也是自动变量。例如: auto int a=2,b; int

4、a=2,b;,上述两种定义方法是等价的,即都定义了a和b为自动变量。每当进入函数体或复合语句时,系统在动态数据区为自动变量分配临时内存单元,退出时自动释放这些内存单元;再次进入函数或复合语句时,系统又为它们重新分配临时内存单元,退出时又自动释放这些内存单元。因此,释放后自动变量的值不可能保留,这类变量的作用域及生命期只存在于定义它的函数体内或复合语句内。,自动变量在动态数据区分配内存单元,并随着程序的运行可能不断释放和重新分配内存单元,也即这个内存单元的位置是不固定的,因此自动变量中的值也会随之改变。所以,自动变量在使用之前必须赋值,否则它的值是不确定的。此外,在不同函数中使用的同名自动变量也

5、不会相互影响。,例9.1 分析下面程序的运行结果。 #include void fun(); void main() fun(); fun(); void fun() int n=2; /*自动变量*/ n+; printf(“n=%dn“,n); ,解 在程序中,函数fun中定义的n为自动变量,其作用域只在函数fun内。第一次调用fun时,为n分配临时内存单元且n的初值为2,执行“n+;”后n值为3,因此输出结果为3;第一次调用fun结束,此时分配给n的内存单元被释放。第二次调用fun时,又为n重新分配了内存单元,函数fun的执行过程与第一次一样,因此输出的结果仍是3。程序执行的动态图如图9

6、-2所示。,图9-2 程序执行的动态图,程序执行后的输出结果为: n=3 n=3,3. 寄存器变量 寄存器变量也是自动变量,它与一般自动变量的区别在于,寄存器变量的值是存储于CPU内的寄存器中,而一般的自动变量则存储于内存中。由于从寄存器中读取数据要比从内存中读取数据的速度快,所以为了提高运算速度,可以将一些频繁使用的局部变量或形参变量定义为寄存器变量。寄存器变量只要在定义时加上存储类别register即可。例如: register int a;,使用寄存器变量时要注意以下几点: (1) 寄存器变量本身是一个自动变量,因此只有函数内定义的变量或形参才可以定义为寄存器变量。 (2) CPU中的寄

7、存器个数有限,所以只能将少数的变量定义为寄存器变量。 (3) 受寄存器长度的限制,寄存器变量只能是char、int和指针类型的变量。 (4) 由于寄存器变量是保存在CPU的寄存器中而不是保存在内存中,因此不能进行取地址运算。 (5) 在调用函数时,函数中的寄存器变量才占用寄存器存放其值,当函数调用结束时就释放寄存器,也即寄存器变量消失。,例9.2 编写求n! 的程序。 解 程序如下: #include long fac(int n); void main() int n; long f; printf(“Input n=“); scanf(“%d“, long fac(int n) regis

8、ter long t=1; register int k; for(k=2;k=n;k+) t=t*k; return (t); ,运行结果: Input n=5 5!=120 在程序中,由于函数fac中的变量t和k频繁使用,故将其定义为寄存器变量。,4. 静态变量 静态变量的存储空间为内存中的静态数据区,该区域中的数据在整个程序运行期间一直占用分配给它们的存储空间,直到整个程序结束。 特别要注意的是,函数体内如果在定义静态变量(称为局部静态变量)的同时进行了初始化,则以后程序不再对其进行初始化操作。这是由于第一次遇见局部静态变量时,系统即为局部静态变量分配了专用的内存单元并将初始化值送入这个

9、内存单元,此后该局部静态变量就一直使用这个内存单元,而无论函数的调用或结束;也即,下一次函数调用时,这个局部静态变量仍然使用这个内存单元,而且并不重新初始化。这样,局部静态变量就可以保存前一次函数调用得到的值而用于下一次函数调用;这一点是局部静态变量与自动变量的本质区别。,局部静态变量的初值是在程序编译时赋予的,在程序执行过程中不再赋值。对没有赋初值的局部静态变量,编译系统自动给它赋初值0。 auto型局部变量与static型局部变量的区别如表9.1所示。,表9.1 auto型局部变量与static型局部变量的区别,例9.3 分析下面程序的运行结果。 #include void fun();

10、void main() fun(); fun(); void fun() static int n=2; /*局部静态变量*/ n+; printf(“n=%dn“,n); ,解 在程序中,函数fun中定义的n为局部静态变量;其作用域只在函数fun内。在程序执行开始前,系统已为n分配了内存单元且n的初值为2,第一次函数fun调用时,执行“n+;”后n值为3,输出3;第一次调用fun函数结束,但系统分配给n的内存单元并不释放。第二次调用fun时,执行“n+;”后n值由3变为4 (注意,不执行对静态局部变量的初始化操作static int n=2),故输出结果为4。所以,程序执行后的输出结果为:

11、n=3 n=4,例9.4 分析下面程序的运行结果。 #include int fun(int x,int y); void main() int j=4,m=1,k; k=fun(j,m); printf(“%d,“,k); k=fun(j,m); printf(“%dn“,k);, int fun(int x,int y) static int m=0,i=2; i=i+m+1; m=i+x+y; return m; ,解 程序执行的动态图如图9-3所示。,图9-3 程序执行的动态图,由于静态局部变量在每次函数调用结束时并不消失,所以在动态图中,我们将静态局部变量m和i放置于函数fun空间的

12、开始处,并且当函数fun结束时,它们仍然存在(在动态图上是用一条横线将它们与局部自动变量分开,且这条线一直持续到程序结束)。在下一次调用函数fun时,仍可使用它们的值。由动态图可知,程序的运行结果为:8,17。,9.2 指向函数的指针变量,在C语言中,一个函数所对应的程序代码总是存放在一段连续的内存区域内,并且像数组名代表数组的首地址一样,函数名就代表该函数代码所占内存区域的首地址。不同的函数有不同的首地址。因此,函数名可以看做为是一个广义的变量,我们可以把这个“变量”函数名(函数的首地址)赋给一个指针变量,使该指针变量指向这个函数,然后通过指针变量就可以找到并且调用执行这个函数。这种指向函数

13、的指针变量就称为“函数指针变量”。,1. 函数指针变量的定义与初始化 函数指针变量定义的一般形式为 类型说明符 (*指针变量名)(); 其中,类型说明符表示被指向的那个函数的返回值类型,“(*指针变量名)”表示“*”后面的变量名是一个指针变量,最后的空括号“()”表示这个指针变量的指向是一个函数。 例如: int(*p)();,定义了p是一个指向函数的指针变量,该函数的返回值为整型。p是用来存放函数的入口地址的,在没有赋值前它不指向任何一个具体函数,并具有一个空指针值。 想要通过函数指针变量来实现对某个函数的调用,还必须对函数指针变量进行初始化,即将需要调用的某个函数入口地址赋给它;由于函数名

14、代表该函数的入口地址,因此是将某个函数名赋给函数指针变量。,函数指针变量初始化的方式有两种:一种是直接赋值;一种是加地址运算符“,函数的指针变量与普通指针变量都能实现间接访问,其唯一的区别是:普通指针变量指向的是内存的数据存储区,而函数的指针变量指向的是内存的程序代码区。因此,普通指针变量的“ * ”运算是访问内存中的数据,而函数的指针变量执行“ * ”运算时,其结果是使程序控制转移到由函数指针变量所指向的函数入口地址,并开始执行该函数。此外,形式参数表也与第5章函数中的形式参数表不同,只能给出形参的类型。,2. 用函数指针变量调用函数 定义了函数指针变量并初始化后,就可以在程序中通过函数指针

15、变量来调用所需要的函数了。调用函数的一般形式为 (*指针变量名)(实参表) 由于优先级不同,所以“*指针变量名”必须用圆括号“( )”括起来,表示间接调用指针变量所指向的函数,而后面的圆括号“( )”中的内容为传递给被调函数的实参。,例9.5 用函数指针调用函数的方式实现在两数中找出最大数的程序。 #include int max(int a,int b); void main() int (*p)(int,int); int x,y,z; p=max; printf(“Input two numbers:n“);,scanf(“%d,%d“, ,运行结果: Input two numbers

16、: 88,66 max=88,从程序中可以看出,用函数指针变量形式调用函数的步骤如下: (1) 先定义函数指针变量;如程序中的“int (*p)(int,int);语句”。 (2) 将被调函数的入口地址(即函数名)赋给函数指针变量;如程序中的“p=max;”语句。 (3) 用函数指针变量形式来调用函数;如程序中的“z=(*p)(x,y);”语句。,例9.6 分析下面程序运行的结果。 #include float f1(float n); float f2(float n); void main() float (*p1)(float),(*p2)(float),(*t)(float),y1,y2;,p1=f1; p2=f2; y1=p2(p1(2.0); t=p1;p1=p2;p2=t; y2=p2(p1(2.0); printf(“%3.0f,%3.0fn“,y1,y2); ,float f1(float n) return n*n;

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号