c++编程自定义函数

上传人:人*** 文档编号:592313463 上传时间:2024-09-20 格式:PPT 页数:92 大小:2.49MB
返回 下载 相关 举报
c++编程自定义函数_第1页
第1页 / 共92页
c++编程自定义函数_第2页
第2页 / 共92页
c++编程自定义函数_第3页
第3页 / 共92页
c++编程自定义函数_第4页
第4页 / 共92页
c++编程自定义函数_第5页
第5页 / 共92页
点击查看更多>>
资源描述

《c++编程自定义函数》由会员分享,可在线阅读,更多相关《c++编程自定义函数(92页珍藏版)》请在金锄头文库上搜索。

1、1第2-4讲 自定义函数函数的根本知识函数的根本知识函数的定义函数的定义函数的参数函数的参数函数的返回值函数的返回值函数的调用函数的调用函数调用的一般形式函数调用的一般形式调用的方式调用的方式嵌套调用嵌套调用递归调用递归调用函数与数组函数与数组局部变量和全局变量局部变量和全局变量变量的动态存储方式和静态存储方式变量的动态存储方式和静态存储方式24.1 概述C语言函数分为两类:库函数scanf printf sqrt cos strcmp自定义函数main每个程序必须有一个main函数说明程序运行的起始点只用一个main编程,可能使程序太大、太复杂例4-1,输出如下图内容:34在面向过程的程序设

2、计中,一个较为复杂的程序一般通在面向过程的程序设计中,一个较为复杂的程序一般通过模块化,分解成主模块与假设干子模块的组合,即一过模块化,分解成主模块与假设干子模块的组合,即一个主函数与假设干子函数。个主函数与假设干子函数。“分的优点:分的优点:便于自上而下的模块化编程;便于自上而下的模块化编程;通过在适当的地方使用函数,可以减短源程序的长度;通过在适当的地方使用函数,可以减短源程序的长度;更容易定位和隔离有错误的函数,便于进一步的检查;更容易定位和隔离有错误的函数,便于进一步的检查;函数可以被其他多个程序使用。函数可以被其他多个程序使用。模块化程序设计模块化程序设计可以把大型程序组织成小而独立

3、的程序段模块,它可以把大型程序组织成小而独立的程序段模块,它们单独命名,是单个的可调用的程序单元。们单独命名,是单个的可调用的程序单元。在在C语言中,每个模块就是一个函数,负责完成单个任语言中,每个模块就是一个函数,负责完成单个任务。务。C语言程序一般都由许多小的函数组成。语言程序一般都由许多小的函数组成。5模块化程序设计的特征:模块化程序设计的特征:每个模块只做一件事情。每个模块只做一件事情。模块之间的通信只允许通过调用模块来实现。模块之间的通信只允许通过调用模块来实现。某个模块只能被更高一级的模块调用。某个模块只能被更高一级的模块调用。如果不存在调用与被调用关系,模块之间是不能直接如果不存

4、在调用与被调用关系,模块之间是不能直接通信的。通信的。所有模块都是使用控制结构设计成单入口、单出口的所有模块都是使用控制结构设计成单入口、单出口的系统。系统。6例例4-2,将例,将例4-1中重复执行的局部改写成函数中重复执行的局部改写成函数/ 函数声明函数声明 原型原型 / 函数函数调用用/ 函数定函数定义义 函数体函数体 函数派生数据类型函数名标识符函数具有与之相关的类型使用之前,函数名及其类型必须已经声明和定义。7多函数程序函数就是含有执行某个特定任务的代码块。函数一旦设计和封装后,就可以看作是一个“黑盒子,它从主程序中获得一些数据,并返回一个值。函数操作的内部细节对程序的其他局部是不可见

5、的。程序所知道的函数就是:输入什么数据以及输出什么数据。每个C程序至少包含一个函数,即main函数主函数。由主函数调用其它函数,其它函数也可以互相调用。同一个函数可以被一个或多个函数调用任意屡次。一个程序可以保存在一个或多个源文件中。各个文件可以单独编译,并可以与库中已编译过的函数一起加载。84.2 函数的根本知识一、函数的定义 包括以下元素包括以下元素函数名函数名函数类型函数类型参数列表参数列表局部变量声明局部变量声明函数语句函数语句返回语句返回语句函数函数头函数体函数体9 函数定义的一般格式:函数定义的一般格式:函数类型函数类型 函数名形式参数列表函数名形式参数列表/函数头,函数头,末尾没

6、有;末尾没有; 局部变量声明;局部变量声明; 语句语句1; 语句语句2; . return 语句;语句;函数类型,即函数带回来的值的类型。函数类型,即函数带回来的值的类型。缺省为缺省为int。如不返回任何值,那么函数类型应指定为如不返回任何值,那么函数类型应指定为void也是也是C的根本类型之一的根本类型之一10形参,以接收从调用函数发送来的数据。形参,以接收从调用函数发送来的数据。形参列表包含了变量的声明,变量之间用逗号分隔开;形参列表包含了变量的声明,变量之间用逗号分隔开;一般格式为:一般格式为:type1 name1, type2 name2, , type n name n其中:其中:

7、 type1 , type2 , type n 是类型标识符,是类型标识符,表示形参的类型;表示形参的类型; name1, name2, , name n 是是形参名。形参名。float quadratic(int a, int b, intc) .double power(double x, int n) .float mul(float x, float y) .int sum(int a, int b) .int sum(int a, b) . 错错形参可以没有,即形参可以没有,即“无参函数。可以在参数列表的无参函数。可以在参数列表的括号中使用关键字括号中使用关键字voidvoid Pr

8、intLine(void) .函数在没被调用时,形参只是一个符号。只有函数在函数在没被调用时,形参只是一个符号。只有函数在被调用时,才由主调函数将实际参数实参赋予形被调用时,才由主调函数将实际参数实参赋予形参。参。11函数体,包含了函数声明及完成任务所需的语句。依函数体,包含了函数声明及完成任务所需的语句。依次为:次为:1) 局部变量,即本函数所需的变量;局部变量,即本函数所需的变量;2) 完成函数任务的语句;完成函数任务的语句;3) return 语句,返回函数所得的值。语句,返回函数所得的值。不返回函数值可以省略不返回函数值可以省略return语句,但要注意把函数语句,但要注意把函数的返回

9、类型声明为的返回类型声明为void。函数体可以为空,即函数体可以为空,即“空函数。此函数不作任何工空函数。此函数不作任何工作,没有任何实际作业。可先占位,再补充作,没有任何实际作业。可先占位,再补充几种典型的例如:几种典型的例如:1213函数的类型和返回值函数的类型和返回值函数的返回值类型应当属于某个确定的类型。如果在定函数的返回值类型应当属于某个确定的类型。如果在定义函数时不指定函数类型,系统会隐含指定函数类型为义函数时不指定函数类型,系统会隐含指定函数类型为int,函数结束也需返回一个,函数结束也需返回一个int型值。型值。函数的返回值由函数的返回值由 return 语句给出。语句给出。

10、return表达式;表达式; 或或 return 表达式;表达式;如果函数没有返回值,函数名前的类型标识符为如果函数没有返回值,函数名前的类型标识符为void,return 语句可省略不写。语句可省略不写。 如果如果return中的值与函数值的类型不一致,那么以函中的值与函数值的类型不一致,那么以函数类型为准。即在返回时先作隐含的类型转换,然后再数类型为准。即在返回时先作隐含的类型转换,然后再返回。返回。/ 3.5 被被转换成成 3 后返回后返回给主函数主函数14例例4-3,编写一个函数用于获取三个整数的最大,编写一个函数用于获取三个整数的最大值。值。15二、函数的调用函数的调用一般格式: 函

11、数名 实参列表; 实参列表中的参数应与函数原型中形参的个数相同、类型相符 一一对应。 主调函数向被调函数以值传递的方式传递。1617 函数调用的执行过程函数调用的执行过程main( ) mul(10,5)调调 mul(10,5) 返回返回 结束结束保存:返回地址当前现场恢复:主调程序现场返回地址18函数调用的方式函数调用的方式 函数调用可以作为一条语句出现,这时函数可以没有函数调用可以作为一条语句出现,这时函数可以没有返回值。返回值。PrintLine();函数调用也可以出现在表达式中,这时必须有一个明函数调用也可以出现在表达式中,这时必须有一个明确的返回值。确的返回值。a=mul(10,5)

12、;printf(%dn, mul(a, b) );If( mul(m, n) total ) printf(Large);函数不能用在赋值语句的左边。函数不能用在赋值语句的左边。 mul(a, b) 15; 错 19函数的嵌套调用函数的嵌套调用 C语言语言 不允许函数嵌套定义,即:在函数定义中再不允许函数嵌套定义,即:在函数定义中再定义一个函数是非法的。定义一个函数是非法的。C语言的函数定义都是互相平行、独立的。语言的函数定义都是互相平行、独立的。C语言可以嵌套调用函数,即在调用函数的过程中,语言可以嵌套调用函数,即在调用函数的过程中,又调用另一个函数。又调用另一个函数。main( ) 结束结

13、束 return returnfun1( )调调fun1( ) fun( ) 调调fun( )20例例4-4,用函数实现,用函数实现21三、函数的声明函数原型 返回类型 函数名形式参数表;函数原型是一条程序语句,必须以分号结束。C程序中的所有函数在使用之前都必须声明,即先声明后使用。如果被调函数的定义出现在主调函数之前,可以不必声明。函数原型声明可在所有函数包括main之前。全局原型,该函数对程序中的所有函数都是可用的。函数原型声明位于某函数定义之中。局部原型,该函数主要是被包含它们的函数使用。标准库函数的函数原型都在头文件中提供,可用 # include 包含这些原型文件。 函数原型和函数定

14、义在返回类型、函数名和参数表上必须完全一致。 函数原型的参数表可不必包含参数名称,而只要包含参数类型即可。例如:例如: int max(int, int,int); 等价于:等价于:int max(int a, int b,int c);22例例4-5,随机函数,随机函数rand 和和srand的使用的使用rand(),返回一个,返回一个0RAND_MAX(32767)之间的之间的随机整数。随机整数。RAND_MAX和和rand定义在头文件中定义在头文件中计算机产生的是一个伪随机数,即这个随机数序列计算机产生的是一个伪随机数,即这个随机数序列有一个长度,会出现重复有一个长度,会出现重复用用sr

15、and(int seed),其参数称为随机数序列种子。,其参数称为随机数序列种子。即不同的伪随机数序列种子,可以得到不同的伪随即不同的伪随机数序列种子,可以得到不同的伪随机数序列。一般采用系统时间作为随机数序列种子,机数序列。一般采用系统时间作为随机数序列种子,例如:例如: srand(unsigned int) time(NULL);23244.3 函数的类型根据是否有参数,是否有返回值,可以将函数分为根据是否有参数,是否有返回值,可以将函数分为以下几种类型:以下几种类型:类型类型1:无参数、无返回值的函数。:无参数、无返回值的函数。类型类型2:有参数、无返回值的函数。:有参数、无返回值的函

16、数。类型类型3:有参数、有返回值的函数。:有参数、有返回值的函数。类型类型4:无参数、有返回值的函数。:无参数、有返回值的函数。25一、无参数、无返回值的函数当函数没有参数时,不用从调用函数接收任何数据。当函数没有参数时,不用从调用函数接收任何数据。同样,它也不返回值,调用函数不会从被调用函同样,它也不返回值,调用函数不会从被调用函数中接收任何数据。数中接收任何数据。 function1() . . function2() . . function2() . . . . . 控制控制无输入无输出26例例4-6,请编写一个含有多个函数的程序,这些,请编写一个含有多个函数的程序,这些函数之间不进行

17、任何数据通信。函数之间不进行任何数据通信。2728二、有参数、无返回值的函数调用函数和被调用函数之间的数据通信情况:调用函数和被调用函数之间的数据通信情况: function1() . . function2(a) . . function2(x) . . . . . 参数值无返回值29实参和形参在数量、类型和顺序上必须匹配。实实参和形参在数量、类型和顺序上必须匹配。实参的值被逐个赋给形参参的值被逐个赋给形参 main() . function1(a1, a2, a3, ., am) . function1(f1, f2, f3, ., fn) . . 函数调用被函数调用实参形参30必须保证函

18、数调用有匹配的参数。必须保证函数调用有匹配的参数。实参实参形参,多余的实参将被丢弃;形参,多余的实参将被丢弃;实参实参形参,未匹配的形参将被初始化为垃圾值;形参,未匹配的形参将被初始化为垃圾值;数据类型的任何不匹配情况都将导致传递垃圾值。数据类型的任何不匹配情况都将导致传递垃圾值。形参必须是有效的变量名,而实参可以是变量名、表形参必须是有效的变量名,而实参可以是变量名、表达式或常量达式或常量实参到形参的传递实现的是实参到形参的传递实现的是值值的传递。被调函数中发的传递。被调函数中发生的一切不会影响到实参中的变量。生的一切不会影响到实参中的变量。例例4-7,修改例,修改例4-6,使得在调用函数中

19、包含参数。,使得在调用函数中包含参数。 void PrintLine(char ch); void value(float p, float r, int n);313233三、有参数、有返回值的函数为确保程序间更高的可移植性,函数编码中往往不为确保程序间更高的可移植性,函数编码中往往不包含任何包含任何I/O操作。操作。调用函数与被调用函数之间具有双向通信。调用函数与被调用函数之间具有双向通信。 function1() . . function2(a) . . function2(x) . . . . return(b); 参数值函数结果34例例4-8,修改例,修改例4-7中的中的value函

20、数,使其能将计函数,使其能将计算的算的sum值返回给值返回给main函数,由函数,由main函数按要函数按要求实现输出。同时扩展求实现输出。同时扩展PrintLine函数,可将显示函数,可将显示字符的长度作为参数传递。字符的长度作为参数传递。3536四、无参数但有一个返回值的函数例例4-9,设计一个与,设计一个与getchar 类似的函数来获取一类似的函数来获取一个整数。个整数。374.4 函数调用时参数的传递在函数未被调用时,函数的形参并不占有实际的内存空在函数未被调用时,函数的形参并不占有实际的内存空间,也没有实际的值。间,也没有实际的值。 只有在函数被调用时才为形参分配存储单元,并将实参

21、只有在函数被调用时才为形参分配存储单元,并将实参与形参结合。与形参结合。 实参类型必须与形参相符。实参类型必须与形参相符。 函数的参数传递指的就是形参与实参结合的过程。函数的参数传递指的就是形参与实参结合的过程。一、值调用 传值调用 直接将实参的值传递给形参。直接将实参的值传递给形参。 单向传递。单向传递。 形参的改变不会影响到实参。形参的改变不会影响到实参。38例例4-10,传值调用,将两个数的值换位。,传值调用,将两个数的值换位。39执行主函数中的函数执行主函数中的函数调用语句:调用语句:swap(x,y);11xa22yb在在swap 子函数中:子函数中:1x2y1a2b1x2y1x2y

22、2a2b2a1btemp = a;a = b;b = temp;1temp1x2y1temp1temp返回主函数后:返回主函数后:40 例例4-11,从键盘上输入字符,要求输入字符为,从键盘上输入字符,要求输入字符为0-9十个数字。十个数字。41二、 数组作为函数参数 数组元素数组元素可以作为调用函数时的实参,用法同单可以作为调用函数时的实参,用法同单个变量,是单向传递个变量,是单向传递 数组名数组名做函数的参数做函数的参数函数调用时只需传递数组名。函数调用时只需传递数组名。 在函数定义中,形参的类型必须与实参数组的相同,数在函数定义中,形参的类型必须与实参数组的相同,数组的大小不必指定。组的

23、大小不必指定。 函数原型中的参数也必须定义为一个数组。函数原型中的参数也必须定义为一个数组。 例例4-12:调用一个函数求数组元素之和:调用一个函数求数组元素之和4243 在C语言中,数组名表示的是该数组的第一个元素的地址。 传递数组名时,实际上是把数组的地址传递给被调用函数。这样被调用函数中的数组就指向内存中相同的数组了。因此,在被调函数中,对形参数组元素的任何修改都将反映到调用函数的原始数组(实参数组)中。 把参数的地址传递给函数称为地址传递(pass by address)或指针传递。谨 记44例例4-13, 请编写一个程序,使用一个函数来请编写一个程序,使用一个函数来把有把有10个个整

24、数整数元素的数组按升序排列元素的数组按升序排列4546例例4-14:调用一个函数求二维数组元素的最大值:调用一个函数求二维数组元素的最大值47例例4-15:矩阵乘法:矩阵乘法484950三、结构体作为函数的参数分别传递各个结构成员分别传递各个结构成员像普通变量一样来处理;像普通变量一样来处理;如果结构很大,该方法就变得难以控制,效率也不高。如果结构很大,该方法就变得难以控制,效率也不高。传递整个结构传递整个结构将整个结构的副本传递给被调函数,函数对结构成员将整个结构的副本传递给被调函数,函数对结构成员的任何修改都不会影响实参。的任何修改都不会影响实参。51例,编写几个对点和矩形操作的函数。例,

25、编写几个对点和矩形操作的函数。定义点的结构类型定义点的结构类型定义矩形的结构类型定义矩形的结构类型521. 定义函数定义函数makepoint,它带有两个整型参数,它带有两个整型参数,并返回一个并返回一个point类型的结构类型的结构532. addpoint函数:将两个点相加函数:将两个点相加54注意要点:注意要点:当函数的参数是一个结构类型时,主调、被调函当函数的参数是一个结构类型时,主调、被调函数中相对应的实参、形参必须为相同的结构类型。数中相对应的实参、形参必须为相同的结构类型。当函数的返回值是一个结构时,必须将返回值赋当函数的返回值是一个结构时,必须将返回值赋给调用函数中的相同类型的

26、结构变量。给调用函数中的相同类型的结构变量。和其它类型的参数一样,结构类型的参数也是通和其它类型的参数一样,结构类型的参数也是通过过“值传递的。值传递的。例例4-16,以将,以将3个学生按成绩由高到低排序为例个学生按成绩由高到低排序为例55564.5 函数的递归调用函数可以直接或间接地调用自身,称为函数可以直接或间接地调用自身,称为递归调用递归调用。直接调用:直接调用:间接调用:间接调用:void fun1(void) fun1( ); / 调用用fun1自身自身 void fun1(void) fun2( ); void fun2(void) fun1( ); 57 递归的条件递归的条件1须

27、有完成函数任务的语句。须有完成函数任务的语句。2有一个确定是否能防止无限的递归调用的测试。有一个确定是否能防止无限的递归调用的测试。3一个递归调用语句。该语句的参数应该逐渐逼一个递归调用语句。该语句的参数应该逐渐逼近不满足条件,以致最后断绝递归。近不满足条件,以致最后断绝递归。4先测试,后递归调用。先测试,后递归调用。#include void count(int val) / 递归函数可以没有返回值递归函数可以没有返回值 if (val 1) count(val -1); printf(ok:, val); / 显示:显示:“ok:整数值:整数值 printf(n);58例例4-17,有,有

28、5个人坐在一起,问第个人坐在一起,问第5个人多少岁个人多少岁?他说比第?他说比第4个人大个人大2岁。问第岁。问第4个人岁数,他个人岁数,他说比第说比第3个人大个人大2岁。问第岁。问第3个人岁数,他又说个人岁数,他又说比第比第2个人大个人大2岁。问第岁。问第2个人岁数,他说比第个人岁数,他说比第1个人大个人大2岁。最后问第岁。最后问第1个人,他说是个人,他说是10岁。请岁。请问第问第5个人多大?个人多大?“推理推理age(5) = age(4) + 2age(4) = age(3) + 2age(3) = age(2) + 2age(2) = age(1) + 2age(1) = 1“总结总结

29、由此计算出由此计算出各年龄各年龄59递归的过程:递归的过程:第一阶段:回归。第一阶段:回归。第二阶段:递推。第二阶段:递推。60例例4-18, 计算计算n!以以5!为例,求值过程:为例,求值过程:5!5*4*3*2*15*(4!)5!5 * 4!4 * 3!3 * 2!2 * 1!1处理递归调用处理递归调用每个递归调用向每个递归调用向调用者的返回值调用者的返回值5!5 * 4!4 * 3!3 * 2!2 * 1!1返回返回1返回返回2!2返回返回3!6返回返回4!24返回返回5!120最后值最后值120616263 例例4-19:汉诺塔问题:汉诺塔问题有三根针有三根针A ,B,C。A针上有针上

30、有n个盘子,盘子大小不等,个盘子,盘子大小不等,大的在下,小的在上,如图示。要求把这大的在下,小的在上,如图示。要求把这n个盘子从个盘子从A针移到针移到C针,在移动过程中可以借助针,在移动过程中可以借助B针,每次只允许针,每次只允许移动一个盘子,且在移动过程中在三根针上都保持大盘移动一个盘子,且在移动过程中在三根针上都保持大盘在下,小盘在上。在下,小盘在上。ABC将将n个盘子从个盘子从A针移到针移到C针可以分解为下面三个步骤:针可以分解为下面三个步骤:1)将将A上上n-1个盘子移到个盘子移到B针上借助针上借助C针;针;2)把把A针上剩下的一个盘子移到针上剩下的一个盘子移到C针上;针上;3)将将

31、n-1个盘子从个盘子从B针移到针移到C针上借助针上借助A针;针;6465递归并不节省存储器的开销,因为递归调用过程中必递归并不节省存储器的开销,因为递归调用过程中必须在某个地方维护一个存储处理值的栈。须在某个地方维护一个存储处理值的栈。递归的执行速度并不快,但递归代码比较紧凑,并且递归的执行速度并不快,但递归代码比较紧凑,并且比相应的非递归代码更易于编写与理解。比相应的非递归代码更易于编写与理解。在描述树等递归定义的数据结构时,使用递归尤其方在描述树等递归定义的数据结构时,使用递归尤其方便。便。664.6 局部变量和全局变量一、局部变量在函数内部定义的变量,仅在该函数内有效。在函数内部定义的变

32、量,仅在该函数内有效。 不同函数中可以使用相同名字的变量,互不干扰。不同函数中可以使用相同名字的变量,互不干扰。 局部变量在定义时没有明确的初始化值。局部变量在定义时没有明确的初始化值。 在函数开始运行时,局部变量在栈区中被分配空间,在函数开始运行时,局部变量在栈区中被分配空间,函数退出时,局部变量随之消失。函数退出时,局部变量随之消失。形式参数也是局部变量。形式参数也是局部变量。例:例: void main( ) void func( ) int s; int s; 67二、全局变量 在任何函数之外定义的变量,也称为外部变量。 可以被本文件中其它函数所共用。它的有效范围是从定义变量的位置开始

33、一直到根源文件结束。 存放在内存的全局数据区。 由编译器建立,默认初始化为0。 int n=5; / 全局变量全局变量 void func( ) void main( ) int s; int m = n; n = s; 68说明说明全局变量的作用是增加了函数之间数据联系的渠全局变量的作用是增加了函数之间数据联系的渠道。道。假设在一个函数中改变了全局变量的值,就能影假设在一个函数中改变了全局变量的值,就能影响到其它函数。响到其它函数。不成文的规定:全局变量的第一个字母用大写表不成文的规定:全局变量的第一个字母用大写表示。示。不在特别必要时,尽量不要使用全局变量不在特别必要时,尽量不要使用全局变

34、量全局变量在程序的全部执行过程中都占用存储单全局变量在程序的全部执行过程中都占用存储单元。元。降低了函数的通用性。假设外部变量与其它文件降低了函数的通用性。假设外部变量与其它文件的变量同名,移植时就会出现问题,降低了程序的变量同名,移植时就会出现问题,降低了程序的可靠性和通用性。的可靠性和通用性。降低程序的清晰性。降低程序的清晰性。一般要求把一般要求把C程序中的函数做成一个封闭体,除程序中的函数做成一个封闭体,除了可以通过了可以通过“实参形参的渠道与外界发生联实参形参的渠道与外界发生联系外,没有其它渠道系外,没有其它渠道移植性好,可读性强。移植性好,可读性强。694.7 作用域与可见性作用域又

35、称作用范围,它指的是标识符的有效范作用域又称作用范围,它指的是标识符的有效范围围 可见性指的是标识符是否可以被引用。可见性指的是标识符是否可以被引用。一、作用域分类函数原型作用域函数原型作用域 是是C 程序中最小的作用域程序中最小的作用域 开始于函数原型声明的左括号,结束于函数原型声明开始于函数原型声明的左括号,结束于函数原型声明的右括号。的右括号。 double area ( double width, double length);70块作用域块作用域局部作用域局部作用域 块是一对块是一对大括号括起来的一段程序大括号括起来的一段程序 块语句块语句 在块中声明的标识符,其作用域从声明处开始,

36、一直在块中声明的标识符,其作用域从声明处开始,一直到块结束的大括号为止。到块结束的大括号为止。 具有块作用域的标识符称作局部标识符。具有块作用域的标识符称作局部标识符。void fun( int y ) / y 的作用域从此开始的作用域从此开始 int a,b; / a, b的作用域从此开始的作用域从此开始 if ( y0 ) int x; / x 的作用域从此开始的作用域从此开始 x = a + b; / x 的作用域到此的作用域到此结束束 / a, b, y 的作用域到此的作用域到此结束束 71void fun( int n) if( n5) int i; i=n; printf(%dn,

37、 i); else double i; i=n; printf(%fn, i); printf(%dn, i); / int i 的作用域从此开始的作用域从此开始/ int i 的作用域到此的作用域到此结束束/ double i 的作用域从此开始的作用域从此开始/ double i 的作用域到此的作用域到此结束束/ error! i 无定无定义72文件作用域文件作用域全局作用域全局作用域 在所有函数定义之外说明;在所有函数定义之外说明; 开始于声明点,结束于文件尾开始于声明点,结束于文件尾(全局变量。全局变量。 在头文件的文件作用域中所进行的声明,假设该在头文件的文件作用域中所进行的声明,假设

38、该头文件被一个源文件嵌入,那么声明的作用域也头文件被一个源文件嵌入,那么声明的作用域也扩展到该源文件中,直到源文件结束。扩展到该源文件中,直到源文件结束。int number;int value; void main( ) a = 1; / error! a 无定义无定义 number = 0; value = number + 1; printf(“%dn, i); int a;73二、可见性 程序运行到某一点,能够引用到的标识符,就是该处可见的标识符。 作用域可见性的一般规那么: 标识符要声明在前,引用在后。 在同一作用域中,不能声明同名的标识符。 在没有互相包含关系的不同的作用域中声明的

39、同名标识符互不影响。 如果在两个或多个具有包含关系的作用域中声明了同名标识符,那么外层标识符在内层不可见。74例例4-20,作用域可见性实例,作用域可见性实例175例例4-21,作用域可见性实例,作用域可见性实例2764.8 变量的存储类型一、动态存储方式与静态存储方式程序的内存区域:程序的内存区域:静态存储方式:在程序的运行期间分配固定的存储空间静态存储方式:在程序的运行期间分配固定的存储空间动态存储方式:在程序的运行期间根据需要进行动态的分动态存储方式:在程序的运行期间根据需要进行动态的分配存储空间。配存储空间。 程序内存空间程序内存空间 代码区代码区(code area)全局数据区全局数

40、据区(data area) 堆区堆区(heap area) 栈区栈区(stack area)存放程序的代码存放程序的代码全局数据和静态数据全局数据和静态数据程序的动态数据程序的动态数据程序的局部数据程序的局部数据77动态存储区存放的数据有:动态存储区存放的数据有:函数的形式参数函数的形式参数自动变量自动变量函数调用时的现场保护和返回地址函数调用时的现场保护和返回地址在程序执行过程中,如果在同一个程序中两次调用同一在程序执行过程中,如果在同一个程序中两次调用同一函数,分配给此函数中局部变量的存储空间地址可能是函数,分配给此函数中局部变量的存储空间地址可能是不相同的。不相同的。C语言中,变量和函数

41、的属性除了具有数据类型外,还语言中,变量和函数的属性除了具有数据类型外,还具有存储类型:具有存储类型: auto自动的:采用堆栈方式分配内存空间,属于自动的:采用堆栈方式分配内存空间,属于暂时性存储,其存储空间可以被假设干变量屡次覆盖使暂时性存储,其存储空间可以被假设干变量屡次覆盖使用。用。 static静态的:在内存中是以固定地址存放的,在静态的:在内存中是以固定地址存放的,在整个程序运行期间都有效。整个程序运行期间都有效。 register存放器的:存放在通用存放器中。存放器的:存放在通用存放器中。 extern外部的:在所有函数和程序段中都可引用。外部的:在所有函数和程序段中都可引用。7

42、8二、auto变量函数的形参、其中定义的局部变量等,如不专门声明为static,都是动态地分配存储空间的,数据存储在动态存储区中。 自动变量“auto关键字可以省略。假设在定义变量时不写auto,那么隐含确定为“自动存储类型。程序中大多数变量属于自动变量。auto int a=3, b; int a=3, b; 等价等价79三、用static声明局部变量静态局部变量,在静态存储区内分配存储单元。变量在程序的整个运行期间都不释放。 static int i; static char bufBUFSIZE; 静态存储变量,假设无显式初始化,那么在程序编译时自动初始化为 0。即只初始化一次,以后每次

43、调用函数时不再重新赋初值,而只是保存上次函数调用结束时的值。虽然静态局部变量在函数调用结束后仍然存在,但其它函数是不能引用它的。80例例4-22,静态存储变量举例,静态存储变量举例81第n次调用调用时初值调用结束时的值bcbca+b+c第1次第2次第3次000345111456891082四、register变量局部变量的值直接存放在CPU中的存放器中。只有局部自动变量和形式参数可以作为存放器变量,其它如全局变量、局部静态变量不行。 register int x; register char c; f(register unsigned m, register long n) register

44、 int I; register static int a, b; 错!一个计算机系统中的存放器数目是有限的,不能定义任意多个存放器变量。83五、外部变量即全局变量,是在函数的外部定义的,它的作即全局变量,是在函数的外部定义的,它的作用域为从变量的定义处开始,到本程序文件的用域为从变量的定义处开始,到本程序文件的末尾。末尾。在此作用域中,全局变量可以被程序中的各个在此作用域中,全局变量可以被程序中的各个函数所引用。函数所引用。编译时分配的静态存储区。编译时分配的静态存储区。有时需要用有时需要用extern来声明外部变量,用以扩展来声明外部变量,用以扩展外部变量的作用域。外部变量的作用域。841

45、. 在一个文件内声明外部变量在一个文件内声明外部变量如果不在文件的开头定义外部变量,其有效的作如果不在文件的开头定义外部变量,其有效的作用范围只限于从定义处开始到文件结束。用范围只限于从定义处开始到文件结束。如果在定义点之前的函数想引用该外部变量,那如果在定义点之前的函数想引用该外部变量,那么应在引用之前用么应在引用之前用extern 作作“外部变量声明。外部变量声明。例例4-23,外部变量举例,外部变量举例85862. 在多个文件的程序中声明外部变量在多个文件的程序中声明外部变量 一个一个C程序可以由一个或多个包含假设干函数定义程序可以由一个或多个包含假设干函数定义的源文件组成。的源文件组成

46、。 其中只有一个源文件具有主函数其中只有一个源文件具有主函数 main( ),而其他,而其他的文件不能含有的文件不能含有 main( )。 C的编译器和连接器把构成一个程序的假设干源文的编译器和连接器把构成一个程序的假设干源文件有机地联络在一起,最终产生可执行程序。件有机地联络在一起,最终产生可执行程序。 C语言中,通过建立一个工程文件语言中,通过建立一个工程文件( .prj) ,将多个,将多个源文件构成一个程序。源文件构成一个程序。 构成一个程序的多个源文件之间,如需要用到同一构成一个程序的多个源文件之间,如需要用到同一个外部变量或函数,不能分别在两个文件中各自个外部变量或函数,不能分别在两

47、个文件中各自定义,而是要通过声明数据或函数为外部的定义,而是要通过声明数据或函数为外部的extern来进行沟通。来进行沟通。87例例4-24,由两个文件构成的一个程序。由两个文件构成的一个程序。88带带 extern 的变量说明只是一个变量声明,不是变量定的变量说明只是一个变量声明,不是变量定义。它表示所声明的变量在程序的其它文件中定义分义。它表示所声明的变量在程序的其它文件中定义分配空间。配空间。 如果共同的变量一次都没有定义,或在各个文件中分如果共同的变量一次都没有定义,或在各个文件中分别定义屡次定义,或声明的类型不一致,都会造成别定义屡次定义,或声明的类型不一致,都会造成直接或间接的错误

48、。直接或间接的错误。894.9 内部函数和外部函数一、内部函数只能被本文件中其它函数所调用。在定义内部函数时,在函数类型的声明前面加static。即: static 类型标识符 函数名形参表内部函数又称为静态函数。通常将只能由同一个文件使用的函数和外部变量放在一个文件中,在它们前面加上static。90二、外部函数在定义函数时,如果在函数声明或定义的最左端加上extern,表示该函数是外部函数。外部函数可以供其它文件调用。C语言规定,如果在定义函数时省略extern,那么隐含为外部函数。 默认的函数声明或定义总是extern 的。 所有函数声明一般都放在源文件的开始位置。91例例4-25,从字符串中删除给定的字符。要求用,从字符串中删除给定的字符。要求用外部函数实现删除字符的功能。外部函数实现删除字符的功能。 ,用来实现字符串及字符的输入、输出功能,用来实现字符串及字符的输入、输出功能 DeleteChar函数,用来实现从字符串中删除字符函数,用来实现从字符串中删除字符在中将在中将DeleteChar定义为外部函数定义为外部函数extern DeleteChar(char str , char ch);92

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

最新文档


当前位置:首页 > 商业/管理/HR > 商业计划书

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