Download presentation
Presentation is loading. Please wait.
1
李祥 E-mail:tom_lx@126.com QQ:100756
2
第七章 函数 目录 1 2 3 4 5 6 7 8 有参的加法函数的开发 函数定义的一般形式 函数参数和函数的值 函数的调用
局部变量与全局变量 6 变量的存储类型 7 函数的递归调用 8 模块化程序的编写
3
知识点要求: 技能要求: 教学要求 1 2 3 1 2 3 函数的定义、调用、声明 函数调用时的参数传递的方式、递归调用
全局变量、局部变量、静态变量 技能要求: 1 掌握函数的定义、调用、声明形式 2 理解函数的递归调用 3 理解自动变量和静态变量的区别
4
7.1 有参的加法函数的开发 任务描述: 编写加法函数newAdd,能够实现两个整数的加法。 任务要求:
(1)两个整数都要从外部接收(函数需要使用参数)。 (2)能够正确返回接收到的两个整数的和。 任务分析 以计算器中的加法函数为例,无参无返回值函数的处理过程为:
5
7.1 有参的加法函数的开发 void add( ); //声明无参无返回值函数 int main( ) {
return 0;} void add( ) { //定义无参无返回值函数 int sum, num1, num2; //定义加数变量及求和变量 scanf(“%d%d”,&num1, &num2); //输入两个加数 sum = num1 + num2 ; //计算 printf(“%d + %d = %d\n”, num1, num2, sum); }
6
有参有返回值函数的使用: int newAdd( int num1, int num2 ); //声明函数原型 void main( ) {
int n1, n2, result; scanf(“%d%d”,&n1, &n2); result = newAdd( n1, n2 ); //调用函数 printf(“%d + %d = %d\n”, n1, n2, result); return ; } int newAdd( int num1, int num2 ) //函数定义 { int sum; sum = num1 + num2; //形式参数直接参与计算 return sum; //返回结果
7
7.1 有参的加法函数的开发 涉及知识点 函数的原型声明— int newAdd( int num1, int num2 );
带参函数的调用— result = newAdd( n1, n2 ); 带参函数的定义— int newAdd( int num1, int num2 ) {… } 函数的返回值 return sum;
8
7.2 函数定义的一般形式 7.2.1 函数的分类 函数的分类: 1. 从用户使用的角度分类
函数的分类 函数的分类: 1. 从用户使用的角度分类 (1) 标准函数(库函数):它是系统提供的,用户不必自己定义,可直接使用它们。如sin()、fabs()、sqrt() 函数等,但必须在本文件的开头写上: #include <math.h> (2)用户自定义函数:它是用户为了特定的目的需要自己专门去写的函数。
9
7.2 函数定义的一般形式 2 .从函数形式分类 (1)无参函数:函数名后面的括号中没有任何参数(相当是自变量),调用该函数时也就不必给具体的实际参数。 (2)有参函数:函数名后面的括号中有参数(可以一个或多个),调用该函数就要相应地给出具体的实际参数,如newAdd( n1, n2 );。
10
7.2 函数定义的一般形式 7.2.2 函数的定义形式 函数的结构 函数类型 函数名 函数的说明部分 形式参数 函数体 函数
函数的定义形式 函数类型 函数名 形式参数 函数的说明部分 函数体 函数 函数内的局部变量类型声明 执行语句 函数的结构
11
7.2 函数定义的一般形式 如: void print_star( ) { 1 .无参函数 printf ("***********");
} 1 .无参函数 格式: 类型说明符 函数名( ) { 函数内的局部变量类型声明部分; 执行语句部分; }
12
7.2 函数定义的一般形式 2 .有参函数 格式: 类型说明符 函数名(形参表列) { 函数内的局部变量类型声明部分; 执行语句部分; }
13
7.2 函数定义的一般形式 【例7.1】定义一个求两个数最大值的函数。 int max (int x, int y ) {
int z; //函数内的局部变量声明 if (x>y) z=x; //本行及以下行是执行语句部分 else z=y; return( z ); } 函数名 函数类型 形参类型 函数的值由变量z返回给函数调用处
14
7.2 函数定义的一般形式 3 .空函数 格式: 类型说明符 函数名() { }
类型说明符 函数名() { } 在进行大的软件开发时,用空函数表示此处还有功能没有写完,等以后扩充函数功能时再作补充。
15
7.2 函数定义的一般形式 说明: (1) 函数的类型可以是任何合法的数据类型说明符,用于确定函数值的类型。
(2) 函数名可以是任何合法的标识符(字母、下划线和数字)。 (3) C程序是由一个或多个函数组成的,但仅能有一个主函数。 (4) C程序在执行时是从main函数开始,调用其他函数后该程序返回 main函数。 (5) 所有函数地位平等,可相互调用,但不可相互包含,也不可以调用main函数。
16
7.3 函数参数和函数的值 7.3.1 形式参数和实际参数 函数参数:
形式参数和实际参数 函数参数: (1)形式参数:简称形参,是指定义函数时,函数名后面括弧中的变量,此部分参数在定义函数时没有实际数值,只是形式上的参数而已; (2)实际参数:简称实参,却与之相反,在调用函数时,函数名后括弧中的参数已有确定的值,所以称为实参。 注意:函数调用时会将实参值一一传送给形参。
17
7.3 函数参数和函数的值 【例7.2】求两个整数中的较大数。 解题思路: 用一个函数实现求两个数中的较大数 在主函数中调用此函数并输出结果
18
7.3 函数参数和函数的值 【例7.2】程序代码如下: #include <stdio.h>
int max(int x,int y) { int z; if (x > y) z = x; else z = y; return(z); } void main( ) { int a,b,c; scanf(”%d,%d”,&a,&b); c = max(a,b); printf("max=%d\n",c); return; }
19
7.3 函数参数和函数的值 调用max函数 15,35 #include <stdio.h>
int max(int x,int y) { int z; if (x > y) z = x; else z = y; return(z); } void main( ) { int a,b,c; scanf(”%d,%d”,&a,&b); c = max(a,b); printf("max=%d\n",c); return; } 调用max函数 15,35
20
7.3 函数参数和函数的值 15 35 35 35 15,35 Max=35 #include <stdio.h>
int max(int x,int y) { int z; if (x > y) z = x; else z = y; return(z); } void main( ) { int a,b,c; scanf(”%d,%d”,&a,&b); c = max(a,b); printf("max=%d\n",c); return; } 35 15,35 35 Max=35
21
7.3 函数参数和函数的值 #include <stdio.h> int max(int x,int y) { int z;
if (x > y) z = x; else z = y; return(z); } void main( ) { int a,b,c; scanf(”%d,%d”,&a,&b); c = max(a,b); printf("max=%d\n",c); return; }
22
7.3 函数参数和函数的值 形式参数 实际参数 #include <stdio.h> int max(int x,int y)
{ int z; if (x > y) z = x; else z = y; return(z); } void main( ) { int a,b,c; scanf(”%d,%d”,&a,&b); c = max(a,b); printf("max=%d\n",c); return; }
23
7.3 函数参数和函数的值 在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。在发生函数调用时,函数max的形参被临时分配内存单元。 实参 a 2 3 b 形参 x 2 3 y
24
7.3 函数参数和函数的值 调用结束,形参单元被释放 如果在执行一个被调用函数时,形参的值发生改变,不会改变主调函数的实参的值 实参 a 2
b 形参 x 2 3 y
25
7.3 函数参数和函数的值 观察以下程序的运行结果,并分析原因。 #include <stdio.h>
void swap(int x,int y) { int z; z=x; x=y;y=z; printf("x=%d\n",x); printf("y=%d\n",y); } void main( ) { int a,b,c; a=10;b=20; swap(a,b); printf("a=%d\n",a); printf("b=%d\n",b); return; }
26
7.3 函数参数和函数的值 函数参数小结: (1) 实参可以是常数也可以是变量或表达式,如max(3,a*b) 。
(2) 被调用的形参类型必须说明。 (3) 实参与形参必须一一对应(即个数一样,类型相同或赋值兼容)。 (4) 对于形参,只有在函数被调用时才为其分配内存空间,函数调用结束后其内存空间被释放,这时形参也就不存在了。 (5)参数的传递为“单向”,即只能由实参传递给形参。实参和形参各占用不同的存储单元。
27
7.3 函数参数和函数的值 主调用函数 被调用函数 7.3.2 函数的返回值 函数的返回值 void main( )
{ int a,b,c; scanf(”%d,%d”,&a,&b); c = max(a,b); printf("max=%d\n",c); return; } #include <stdio.h> int max(int x,int y) { int z; if (x > y) z = x; else z = y; return(z); } 函数的返回值
28
7.3 函数参数和函数的值 2.返回函数值语句的一般形式 return (表达式) 如: return (x>y?x:y); 说明:
(2) 一个函数可以有一个以上的return语句,但只有被执行到的return语句起作用,return语句执行完后,被调用函数运行结束。
29
7.3 函数参数和函数的值 【例7.3】输入2个整数,如果都大于0求出它们的和,否则求出它们的差。 解题思路:
单独编写一个函数fun用于求两个数的和或差,在主函数中输入两个整数,再调用fun函数完成问题求解。
30
7.3 函数参数和函数的值 void main ( ) #include <stdio.h> {
int a,b,c; printf("Please input two integer: "); scanf ("%d,%d",&a,&b); c=fun(a,b); printf ("%d\n",c); return ; } #include <stdio.h> fun (int x,int y ) { int z; if (x>0&&y>0) z=x+y; return(z); } else z=x-y;
31
7.3 函数参数和函数的值 3. 函数返回值的类型 函数有一个返回值,则此值有一个确定的类型。这个类型说明应该在函数定义时说明,即函数名前的类型说明符。例如: int max(int x,int y); 该函数类型为int型,函数最终结果值也为int型。 float max(float x,float y); 该函数类型为float型,函数最终结果值也为float型。
32
7.3 函数参数和函数的值 说明: 例: void print_star( ) { … }
(1) C语言规定,凡未加类型说明的函数,其值的类型一律以整型处理。 (2)return中表达式类型要求和函数值的类型一致,否则以函数类型为准,即return中表达式结果类型系统自动隐式转换成函数值类型。 (3) 如果被调用函数中无return语句,其值不带回。 (4) 为了明确表示“不带回值”,可以使用“void”定义“无类型”或“空类型”。此时函数中可以没有return语句。 例: void print_star( ) { … }
33
7.3 函数参数和函数的值 练习: 用带参的函数编写一个函数(函数名为fact),计算整数n的阶层。 提示: 函数的功能:计算n!
34
7.4 函数的调用 7.4.1 函数调用的一般形式 格式: 函数名(实参表列) 说明:
函数调用的一般形式 格式: 函数名(实参表列) 说明: (1) 如果调用无参函数,则实参列表没有,但是括号不可省略; (2) 形参和实参之间应一一对应,故它们之间个数必须一致、类型一致或兼容,且实参之间以","隔开。
35
7.4 函数的调用 【例7.4】函数调用示例。 void main( ) #include <stdio.h> {
int f(int a,int b) { int c; printf("a=%d,b=%d\n",a,b); if(a>b) c=1; else if (a==b) c=0; else c=-1; return(c); } void main( ) { int i=2,p; p=f( i, ++i ); printf("%d\n",p); return; } ++i后i的值为3 i的值为3
36
7.4 函数的调用 函数调用的三种方式: (1) 函数语句:将函数调用作为一条语句,函数不带返回值,只完成某项功能操作。如:print_star(); (2) 函数表达式:函数出现在一个表达式中,函数带回一个确定值以参加表达式的运算。 c=2*max (a,b); (3) 函数参数:函数调用作为一个函数的实参。如: m=max(a,max(b,c)); 10-12班 11.22
37
7.4 函数的调用 7.4.3 对被调用函数的声明 在一个函数中调用另一个函数需要的条件: (1) 被调用函数必须是已存在的函数。
对被调用函数的声明 在一个函数中调用另一个函数需要的条件: (1) 被调用函数必须是已存在的函数。 (2) 如使用库函数,一般应在本文件开头用#include命令, 如: #include "stdio.h"。
38
7.4 函数的调用 (3) 如使用用户自己定义的函数,且该函数与调用它的函数在同一个文件中。但如果被调用函数的位置出现在主调用函数的后面,一般还应在主调用函数中对被调用函数作声明。 声明的作用:把函数名、函数参数的个数和参数类型这些信息通知编译系统,以便对被调用函数的编译检查。
39
7.4 函数的调用 (4) 对第3条,以下几种情况可以不在调用函数中作声明: ① 如函数的值是整型或字符型(系统按整型对待)。
② 如被调用函数的定义出现在主调函数之前,可以不加说明。 ③ 如已在所有函数定义之前,在文件开头、函数的外部已说明了函数类型。
40
原因:该函数定义在函数main的后面!!
【例7.5】输入两个实数,求其和。 #include <stdio.h> void main( ) { float a,b,c; scanf(" %f,%f ",&a,&b); c=add(a,b); printf("sum is %f ",c); return ; } float add(float x, float y) float z; z=x+y; return(z); 编译能通过吗?? 不知道add 是函数名 原因:该函数定义在函数main的后面!!
41
方法一:将add函数定义在函数main的前面面!! OK!!
【例7.5】输入两个实数,求其和。 #include <stdio.h> float add(float x, float y) { float z; z=x+y; return(z); } void main( ) float a,b,c; scanf(" %f,%f ",&a,&b); c=add(a,b); printf("sum is %f ",c); return ; 方法一:将add函数定义在函数main的前面面!! OK!!
42
方法二:对被调用函数add()作声明 !OK
【例7.5】输入两个实数,求其和。 #include <stdio.h> void main( ) { float a,b,c; float add(float x, float y); scanf(" %f,%f ",&a,&b); c=add(a,b); printf("sum is %f ",c); return ; } float add(float x, float y) float z; z=x+y; return(z); 方法二:对被调用函数add()作声明 !OK 还是放在后面 !但前面有声明!
43
7.4 函数的调用 7.4.3 对被调用函数的声明 函数的声明格式: 在函数定义的第一行后面加一个分号。
对被调用函数的声明 函数的声明格式: 在函数定义的第一行后面加一个分号。 如: float add(float x, float y); 函数原型:把函数定义的首行称为函数原型。 因为函数的形参名称只是一种形式名称,用哪一个名称都可以,所以对被调用函数的声明语句中,形参名还可省略。如上面的声明语句可以写为: float add(float, float );
44
7.4 函数的调用 注意: C语言的函数定义是互相平行独立的、并不相互从属 ; 函数不能嵌套定义; 函数可以嵌套调用函数;
程序从main( )函数开始执行; 如自定义函数定义在main( )之前,则在main( )中不必对这些函数进行声明。
45
7.4 函数的调用 练习: 题目:编写计算组合数的程序。 问题分析:
(1)组合数的计算公式为: ,此公式中用到3次阶乘的计算,所以可以调用前面已经编写好的阶层函数fact()。 (2)考虑到组合数的运算结果可能是浮点点数,所以存放结果的变量定义为double型。
46
思考题 仔细阅读以下程序,找出其中的错误并改正。 #include <stdio.h> int main()
{float x,y; printf("%f\n",sum(x+y)); return 0; } sum (float a,float b) {float c; c=x+y; return ;
47
7.5 局部变量和全局变量 7.5.1 局部变量 局部变量:在函数体内说明的变量,其作用范围被限制在该函数之内,并且只从其说明处之后有效。
局部变量 局部变量:在函数体内说明的变量,其作用范围被限制在该函数之内,并且只从其说明处之后有效。 C语言规定: (1)主函数内定义的变量也是局部变量,只能在主函数中有效。 (2)函数定义时的形式参数也是局部变量,只能在说明它的函数中使用。 网络工程
48
7.5 局部变量和全局变量 C语言规定: (3)不同函数可以有相同名称的局部变量,它们代表不同的变量对象,且互不影响。
(4)在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为“分程序”或“程序块”。 网络工程
49
7.5 局部变量和全局变量 float f1( int a) { int b,c; …… } char f2(int x,int y)
{ int i,j; a、b、c仅在此函数内有效 x、y、i、j仅在此函数内有效
50
7.5 局部变量和全局变量 int main ( ) { int a,b; …… { int c; c=a+b;
} c仅在此程序块(也称复合语句)内有效 a、b在整个main函数内有效
51
7.5 局部变量和全局变量 全局变量 全局变量:在函数定义之外说明的变量称为全局变量(外部)变量。全局变量作用范围比局部变量大,从说明该变量处起,之后所有的函数都可以使用它。即有效范围为从定义变量的位置开始到本源文件结束。
52
7.5 局部变量和全局变量 从使用范围上看: 使用局部变量的目的是避免一个函数中的变量被其他函数使用;
使用全局变量的目的是为了使几个函数共同使用同一个变量,以便函数间进行数据传递和处理。 使用全局变量过多,将会严重降低程序的可读性,所以建议尽量减少使用全局变量。
53
7.5 局部变量和全局变量 int p=1,q=5 float f1(int a) { int b,c; …… } char c1,c2; char f2 (int x, int y) { int i,j; …… } int main ( ) { int m,n; …… } p、q、c1、c2为全局变量 p、q、c1、c2为全局变量
54
7.5 局部变量和全局变量 int p=1,q=5 float f1(int a) { int b,c; …… } char c1,c2; char f2 (int x, int y) { int i,j; …… } int main ( ) { int m,n; …… } p、q的有效范围 c1、c2的有效范围
55
7.5 局部变量和全局变量 【例7.6】 说明: (1) 如果一个函数使用的全局变量在该函数后说明,则应用extern进行外部变量说明。
void main() { int max(int,int); extern A,B; printf(“%d”,max(A,B)); } int A=13,B=-8; int max(int x,int y) int z; z=x>y?x:y; return(z); 说明: (1) 如果一个函数使用的全局变量在该函数后说明,则应用extern进行外部变量说明。
56
7.5 局部变量和全局变量 说明: (2) 在一个函数中,如果全局变量与局部变量同名,则只有局部变量有效,即同名局部优先。见例7.7。
57
#include <stdio.h> int a=3,b=5; int main() { int max(int a,int b); int a=8; printf(“max=%d\n”,max(a,b)); return 0; } int max(int a,int b) { int c; c=a>b?a:b; return(c); } b为全局变量 a为局部变量,仅在此函数内有效
58
#include <stdio.h> int a=3,b=5; int main() { int max(int a,int b); int a=8; printf(“max=%d\n”,max(a,b)); return 0; } int max(int a,int b) { int c; c=a>b?a:b; return(c); } a、b为局部变量,仅在此函数内有效
59
7.6 变量的存储类型 7.6.1 变量存储类型 变量应从“数据类型”和“存储类型”两个方面进行描述。
变量存储类型 变量应从“数据类型”和“存储类型”两个方面进行描述。 从变量的存储类型主要可以分为四种:动态存储、外部存储、静态存储和寄存器变量,C语言中分别用auto、extern、static、register加以说明。存储类别说明符主要是用来告诉编译程序,其后的变量应该如何存储。
60
7.6 变量的存储类型 7.6.1 变量存储类型 从变量的作用范围来分类,变量可以分为局部变量和全局变量。
变量存储类型 从变量的作用范围来分类,变量可以分为局部变量和全局变量。 从变量值存在的时间(即生存期)观察,可分为两种不同的存储变量:静态存储变量和动态存储变量; 静态存储变量:在程序运行期间分配固定的存储空间 。 动态存储变量:程序运行时根据需要进行动态分配存储空间的方式 。
61
7.6 变量的存储类型 程序区 静态存储区 动态存储区 将数据存放在此区 内存空间
程序开始执行时给全局变量分配存储区,程序执行完毕就释放。在程序执行过程中占据固定的存储单元 程序区 静态存储区 动态存储区 全局变量全部存放在静态存储区中 ①函数形式参数②函数中定义的没有用关键字static声明的变量③函数调用时的现场保护和返回地址等存放在动态存储区 函数调用开始时分配,函数结束时释放。在程序执行过程中,这种分配和释放是动态的 将数据存放在此区 内存空间
62
7.6 变量的存储类型 7.6.2 局部变量存储方式 1.自动变量(auto变量) 格式: auto 类型名 变量名
局部变量存储方式 1.自动变量(auto变量) 格式: auto 类型名 变量名 自动变量也叫动态变量,存储在动态存储区中,主要是指函数的动态局部变量和形式参数。 自动变量在函数调用开始时动态分配内存单元,函数调用结束时,由系统收回并释放其内存空间。 普通的局部变量均隐含地被认为是auto型,所以一般很少使用auto说明符。
63
7.6 变量的存储类型 自动变量(auto变量) int f(int a) { auto int b=3; ┇ } 可以省略
64
7.6 变量的存储类型 2.静态局部变量(static局部变量) 定义格式: static 类型名 变量名
65
【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3; a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } 每调用一次,开辟新a和b,但c不是 调用三次
66
a c 3 【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3;
a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } a c 第一次调用开始 3
67
a c 1 3 4 【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3;
a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } a c 第一次调用期间 1 3 4
68
a c 1 4 【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3;
a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } 7 a c 第一次调用结束 1 4
69
a c 4 【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3;
a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } a c 第二次调用开始 4
70
a c 1 5 4 【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3;
a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } a c 第二次调用期间 1 5 4
71
a c 1 5 【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3;
a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } 8 a c 第二次调用结束 1 5
72
a c 5 【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3;
a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } a c 第三次调用开始 5
73
a c 1 6 5 【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3;
a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } a c 第三次调用期间 1 6 5
74
a c 1 6 【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3;
a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } 9 a c 第三次调用结束 1 6
75
c 6 【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3; a=a+1;
c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } c 整个程序结束 6
76
【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3; a=a+1; c=c+1; return(a+b+c); } 在函数调用时赋初值 int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } 在编译时赋初值
77
【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3; a=a+1; c=c+1; return(a+b+c); } 若不赋初值,不确定 int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } 若不赋初值,是0
78
【例7.8】 静态变量示例: int f(int b) { auto int a=0; static int c=3; a=a+1; c=c+1; return(a+b+c); } int main() { int b=2,i; for(i=0;i<3;i++) printf(“%d\n”,f(b)); return 0; } 仅在本函数内有效
79
7.6 变量的存储类型 练习: (1)编译并运行右边的程序,观察运行结果。
(2)将函数f中的自动变量改为静态变量,即将auto int j=0改为static int j=0,再次运行程序,观察程序的运行结果。 (3)总结自动变量和静态变量的区别。 #include <stdio.h> void f() {auto int j=0; j++; printf("%d\n",j); } int main() {int i; for (i=1;i<=3;i++) f(); return 0;
80
7.6 变量的存储类型 关于局部静态变量的说明: (1) 局部静态变量属静态存储类别(程序运行期间存储数据不释放),而自动变量不占存储空间(调用结束释放)。 (2) 局部静态变量在编译初期赋值,以后均保留上次调用时的值,而自动变量每调用一次重新赋值。 (3) 在定义局部变量时如不赋初值,则: 静态变量:自动为0; 动态变量:值不固定(因为每次结束释放,下次分配)。
81
7.6 变量的存储类型 思考题: 右边程序的运行结果是? #include <stdio.h> void fun ( )
{ static int b=5; b++; printf("b=%d\n", b); } void main( ) { int i; for (i=0;i<=1;i++) fun( ); return ; 思考题: 右边程序的运行结果是?
82
7.6 变量的存储类型 【例7.9】产生一个由10个随机数组成的序列 (随机数范围:-32~32) 。 解题思路:
设计一个随机数产生函数random_num; 设计一个静态变量ran_num,第一次默认值为0,其后的值分别为每次函数运行后产生的随机数(这里没对范围处理)。 在主函数中循环调用10次函数random_num,并对得到的随机数的范围进行处理。
83
#include <stdio.h >
int random_num(void); void main( ) { int a; for(a=0;a<10;a++) if(a%5==0) printf("\n"); printf("%10d",random_num( )%33); } printf("\n"); int random_num(void) static int ran_num; ran_num=(ran_num* ); return (ran_num);
84
7.6 变量的存储类型 3 寄存器变量(register型)(了解) 格式: register 类型名 变量名 说明:
(1) 由于寄存器变量存储在计算机的CPU中,所以使用寄存器变量要比使用内存变量的操作要快得多,即可以提高执行效率。 (2) 寄存器变量的类型仅限int, char或指向int,char的指针。 (3) 寄存器变量仅适用局部变量或函数的形式参数。 (4) C规定寄存器变量的数目不能超过3个,多余的将按auto处理。
85
7.6 变量的存储类型 7.6.3 全局变量的存储类别 1.外部变量(extern型) 格式: extern 类型名 变量名 例如:
extern int a;
86
7.6 变量的存储类型 使用extern的情况: (1)在一个文件内扩展外部变量的作用域 外部变量有效的作用范围只限于定义处到本文件结束。
87
7.6 变量的存储类型 【例7.10 】调用函数,求3个整数中的大者。
解题思路:用extern声明外部变量,扩展外部变量在程序文件中的作用域。 程序如下:
88
#include <stdio.h> int main() { int max( ); extern int A,B,C; scanf(“%d %d %d”,&A,&B,&C); printf("max is %d\n",max()); return 0; } int A ,B ,C; int max( ) { int m; m=A>B?A:B; if (C>m) m=C; return(m); }
89
7.6 变量的存储类型 (2)将外部变量的作用域扩展到其他文件
如果一个程序包含两个文件,在两个文件中都要用到同一个外部变量Num,不能分别在两个文件中各自定义一个外部变量Num 应在任一个文件中定义外部变量Num,而在另一文件中用extern对Num作“外部变量声明” 在编译和连接时,系统会由此知道Num有“外部链接”,可以从别处找到已定义的外部变量Num,并将在另一文件中定义的外部变量Num的作用域扩展到本文件
90
7.6 变量的存储类型 【 例7.11 】给定b的值,输入a和m,求a*b和am的值。 解题思路:
分别编写两个文件模块,其中文件file1包含主函数,另一个文件file2包含求am的函数。 在file1文件中定义外部变量A,在file2中用extern声明外部变量A,把A的作用域扩展到file2文件。
91
7.6 变量的存储类型 文件file1.c: #include <stdio.h> int A; int main() { int power(int); int b=3,c,d,m; scanf("%d,%d",&A,&m); c=A*b; printf("%d*%d=%d\n",A,b,c); d=power(m); printf("%d**%d=%d\n",A,m,d); return 0; }
92
7.6 变量的存储类型 文件file2.c: extern A; int power(int n) { int i,y=1; for(i=1;i<=n;i++) y*=A; return(y); } 熟悉编译和运行包括多个文件的程序的步骤。
93
7.6 变量的存储类型 2. 静态全局变量(static型) 格式:static 类型名 变量名 例如:static int b;
静态全局变量和普通全局变量的区别在于: 它只说明它在本程序中有效,即虽然它是全局变量,但是其他程序文件中的程序并不知道它的存在,无法改变其内容。
94
7.6 变量的存储类型 只能用于本文件 本文件仍然不能用 file2.c file1.c extern A; static int A;
void fun (int n) { …… A=A*n; …… } file1.c static int A; int main ( ) { …… }
95
7.7 函数的递归调用 函数的递归调用: 在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。
递归有两种形式:直接递归和间接递归。 直接递归: 是指在一个函数中包含对其本身的调用。 间接递归: 是指函数f1在调用其他函数f2时,而函数f2又直接或间接地调用函数f1。
96
7.7 函数的递归调用 int f(int x) { int z; z=f(x); return (2*z); } f函数 调用f函数
直接调用本函数 f1函数 调用f2函数 f2函数 调用f1函数 间接调用本函数 应使用if语句控制结束调用
97
7.7 函数的递归调用 说明:程序中不应该出现无终止的递归调用,而只应出现有限次数的、有终止条件的递归调用。一般使用if语句进行控制,当某一条件成立时继续执行递归调用,否则终止递归调用。 递归问题求解一般需要满足以下三个条件: (1)原问题能够向另一个相对更简单的问题转化。 (2)转化后的问题和原来问题求解类似。 (3)转化能够有一个终止的条件。
98
7.7 函数的递归调用 【例7.12】设n的阶乘定义如下,试编程实现输入一个数n,求其阶乘。 解题思路: n! = (n-1)!×n
… 2!=1! ×1 1!=1
99
#include "stdio.h " long fac(int n) { long f; printf("n=%d",n); if(n<0) printf("\nn<0,data error!"); f=0; } else if(n==0) f=1; else f=fac(n-1)*n; printf("\n return:n=%d f=%ld",n,f); return(f); 此处调用其本身函数,为直接递归
100
void main() { int n;long y; printf("Input a integer number:"); scanf("%d",&n); y=fac(n); if(y!=0) printf("%d!=%ld\n",n,y); return ; } 仔细以上程序运行结果,体会递归的过程。
101
fac函数 n=4 fac函数 n=3 main fac(4) 输出fac(4) f=fac(3)×4 f=fac(2)×3 24 fac(4)=24 fac(3)=6 fac函数 n=0 fac函数 n=1 fac函数 n=2 f=1 f=fac(0)×1 f=fac(1)×2 fac(2)=2 fac(0)=1 fac(1)=1
102
7.7 函数的递归调用 【例7.13】用递归法求Fibonacci数列第n项的值。该数列有如下的特点:第1个数和第2个数都为1,从第3个数开台,每个数都是其前面两个数之和。即: F1= (n=1) F2= (n=2) Fn=Fn-1+Fn (n=3)
103
7.7 函数的递归调用 递归函数形式: long fib(int n) { long f; if(n==0) f=0;
else if(n==1) f=1; else f=fib(n-1)+fib(n-2); return f; } 其它代码?? 此处调用其本身函数,为直接递归 此处调用其本身函数,为直接递归
104
#include <stdio.h>
int pea(int n) {int c; if(______________) c=5; else c=_____________________; return( c ); } void main() {printf(“%d\n”,pea(5)); return; 思考题: 题目:有5只猴子摘桃子,已知第5只比第4只多摘2个,第4只比第3只多摘2个,第3只比第2只多摘2个,第2只比第1只多摘2个,第1只猴子摘了5个,问第5只猴子摘了多少个(用递归实现)
105
7.8 模块化函数的编写 1.写一个判断素数的函数,在主函数输入一个整数,输出是否素数的信息。 要求:
(1)函数名为prime,如果是素数,函数返回值为1,如果不是素数,函数返回值为0。 (2)主函数写在prime函数之前,在函数中对其所调用的函数作声明。 (3)以上程序编译运行之后,对程序进行修改,将主函数移到prime函数之后,删除主函数中的函数声明。 (4)保留判别素数的函数,修改主函数,要求实现输出100~200之前的素数。
106
7.8 模块化函数的编写 2. 求两个整数的最大公约数和最小公倍数。分别用以下两种方法实现。
(1)用两个函数求最大公约数和最小公倍数。两个整数在主函数中输入,通过参数传送给函数gys,求出最大公约数返回主函数,然后再与两个整数一起作为实参传递给函数gbs,求出最小公倍数,在主函数中输出最大公约数和最小公倍数。 (2)用两个全局变量分别代表最大公约数和最小公倍数。用两个函数分别求最大公约数和最小公倍数,但其值不由函数带回,而是赋给全局变量。在主函数中输出它们的值。
107
重点: 难点: 本章小结 1 2 3 1 2 函数的定义、调用及参数传递方式 函数的递归调用 局部变量和全局变量 局部静态变量和动态变量
108
本章结束!
Similar presentations