210 likes | 331 Views
C 语言程序设计. 同学们好!下面开始讲授 C 语言课程的第 12 讲内容。 第 12 讲 函数( 2 ) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例 三、变量的作用域(下) 1 .函数定义体内的自动变量和静态变量 函数定义体内的变量都属于块作用域变量,即局部变量,但根据变量性质又分为 2 种:一种叫自动变量 (auto) ,另一种叫静态变量 (static) 。 注意几点: ( 1 )自动变量定义时如果不赋初值,该变量的值不确定;而静态变量定义时如果不赋初值,该变量的值为 0 。. 第 12 讲 函数( 2 )
E N D
C语言程序设计 同学们好!下面开始讲授C语言课程的第12讲内容。 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例 三、变量的作用域(下) 1.函数定义体内的自动变量和静态变量 函数定义体内的变量都属于块作用域变量,即局部变量,但根据变量性质又分为2种:一种叫自动变量(auto),另一种叫静态变量(static)。 注意几点: (1)自动变量定义时如果不赋初值,该变量的值不确定;而静态变量定义时如果不赋初值,该变量的值为0。 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 (2)C语言规定,函数内部的自动型变量只有在相应的函数被调用时才申请存储空间,一旦调用结束,则立即释放存储空间,换句话说,自动型变量的生命期是相应的函数被调用时,函数调用结束自动型变量的生存期也就结束了;而出现在函数内部的静态变量的生命期是整个程序的执行过程,因此,静态变量有和外部变量(全局变量)一样的生命期。如: void ff() { auto int z=0;//自动变量,不赋初值,值不确定 static int k;//静态变量,第1次自动赋初值0 k+=5;//每次调用此函数在k的原值上加5 z+=5;//每次都在0上加5 } int i; for (i=1; i<=5; i++) ff(); for循环共5次,即调用函数ff()共5次,最后一次调用后静态变量k值为25,而自动变量(auto) z值为5。 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 2.分析变量作用域的程序举例 程序1: #include<stdio.h> #define NN 8//文件域符号常量 int Num[NN]={12,10,8,3,5,0,7,2};//全局域数组 int Sum() {//求全局数组Num[NN]中的所有元素之和 int i,s=0;//i,s为局部变量,作用域为此函数体 for (i=0; i<NN; i++) s+=Num[i]; return s;//返回所求元素之和 } int Max() { //求全局数组Num[NN]中的所有元素的最大值 int i,m=Num[0]; //i,m为局部变量,作用域为此函数体 for(i=1; i<NN; i++) if(Num[i]>m) m=Num[i]; return m; //返回所有元素的最大值 } void main() { int c=0; //局部变量,从此处到主函数结束 c=Sum()+2*Max(); //47+2*12=71 printf("c=%d\n",c); //输出结果:c=71 } 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 程序2: #include<stdio.h> int Mul(int a[], int n); //函数原型声明语句 void main() { int b[5]={1,2,3,4,5};//只作用于主函数的数组 int r1,r2;//只作用于主函数的局部变量 r1=Mul(b,5);//所有元素乘积,值120 r2=Mul(b+2,3);//b[2]*b[3]*b[4],值60 printf("r1=%d, r2=%d\n",r1,r2);//输出:r1=120, r2=60 } int Mul(int a[ ], int n) {//a和n的作用域为该函数 int i,p=1;//局部变量,作用域到复合语句结束 for (i=0; i<n; i++) p*=a[i]; //求a数组中n个元素之积 return p;//返回p的值 } 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 程序3: #include<stdio.h> int x=10; //全局变量 void main() { int y=20; //局部于整个主函数的变量 printf("x=%d, y=%d\n",x,y); //输出:x=10, y=20 { int x=30; //局部于此复合语句内的变量,优先于外部同名变量 y=y+x; //y为外部的,x为内部的 printf("x=%d, y=%d\n",x,y); //输出:x=30, y=50 } //内部的x的作用域就此结束 printf("x=%d, y=%d\n",x,y); //输出:x=10, y=50 } //y作用域就此结束 //全局变量x的作用域到整个程序运行结束 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 程序4: #include<stdio.h> int Cdiv(int m, int n) //求出m和n的最大公约数 { //m和n只作用于此函数 int r; //局部变量 if(m<n) {r=m; m=n; n=r;} //大者放m,小者放n while(r=m%n) {m=n; n=r;} //循环结束时n的值为最大公约数 return n; //返回n值 } void main() { int m,n; //此处的m和n只作用于主函数 printf("输入两个正整数求其最大公约数: "); scanf("%d %d",&m,&n); 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 printf("%d 和 %d 的最大公约数为: %d\n",m,n,Cdiv(m,n)); //进行Cdiv(m,n)调用时,m和n的值分别对应传送, //在Cdiv(m,n)的函数体中对m和n的修改,与此处的m和n无关 } //允许不同作用域的变量同名 运行结果: 输入两个正整数求其最大公约数: 25 40 25和40的最大公约数为:5 程序5: #include<stdio.h> void xk2(); void main() { int i; for(i=1; i<=4; i++) xk2(); 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 } void xk2() { int a=0; //每次调用此函数时都要重新建立a并被初始化 static int b=0; //只在第1次调用时建立和初始化,以后继续使用 a++; b++; printf("a=%d, b=%d\n",a,b);//每次a的值为1,b的值被增1 } 运行结果: a=1, b=1 a=1, b=2 a=1, b=3 a=1, b=4 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 四、递归函数 在C语言程序中,主函数可以调用其他任何函数,任一函数又可以调用除主函数之外的任何函数。特别地,一个函数还可以直接或间接地调用自己,这种情况称为直接或间接递归调用,此函数称为递归函数。直接递归是指在一个函数体中出现调用本函数的表达式,间接递归是指在一个函数中调用另一个函数,而在另一个函数中反过来调用这个函数。这里只简要讨论一下直接递归调用的情况。 若一个问题的求解过程可以化为采用同一方法的较小问题的求解过程,而较小问题的求解过程又可以化为采用同一方法的更小问题的求解过程,依此类推,这种有规律地将原有问题逐渐化小,并且求解大、小问题的方法相同的过程,称为递归求解过程。由于在递归过程中,求解的问题越化越小,最后必然能够得到一个最小问题的解,它不需要再向下递归求解,能够直接得到解,然后再逐层向上返回,依次得到较大问题的解,最终必将得到原有问题的解。 下面用例子来说明递归函数的定义与调用过程。 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 如:设计一个函数,它计算并返回n的阶乘;要求用递归调用实现。 分析:一个整数n的阶乘可表示为n!,并特别规定0!=1,例如5!=5×4×3×2×1=120。阶乘的定义还可以表示为(递归定义): n=0或n=1 n!= n>1 从程序设计角度来说,递归过程必须解决两个问题:一是递归计算的公式,二是递归结束的条件。对求阶乘的递归函数来说,这两个条件可以写成下列公式: 递归计算公式 f(n)=n*f(n-1) 递归结束条件 f(1)=1 下面给出求n!函数f(n)的定义。 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 int f(int n) { if (n==0 || n==1) return 1;//直接返回 else return n*f(n-1);//进行递归调用 } int x=f(5); //递归调用过程:f(5)->5*f(4)->4*f(3)->3*f(2)->2*f(1) //调用返回过程:2*1->3*2->4*6->5*24->120//x=120 又如:利用递归方法求解一维数组a[n]中n个元素之和。 int f7(int a[], int n) { if (n==1) return a[0];//结束递归并返回 else return a[n-1]+f7(a,n-1);//递归调用 } int a[5]={2,5,4,8,6}; int z=f7(a,5); //调用:f7(a,5)->6+f7(a,4)->8+f7(a,3)->4+f7(a,2)->5+f7(a,1) //返回:5+2->4+7->8+11->6+19->25//z=25 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 五、函数指针 (1)函数名是指向该函数执行代码的指针 函数定义:int fa(int x, int y){return x+y;} //则函数名fa的指针类型为int (*) (int, int) (2)定义函数指针变量并赋予同类型函数的函数名(指针)后,可以同函数名一样使用 int (*fp) (int, int)=fa; 则fa(a,b);与 fp(a,b);等价 (3)函数的形参表中也可以使用函数参数 void fc(char*p, int hf(int, int)); //hf为函数形参 //fc(”abcd”, fa);与fc(str, fp);等价 //fa和fp为函数实参 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 (4)使用函数参数的程序举例 #include<stdio.h> int Length(char*p) {int i=0; while(*p++) i++; return i; } void Out(char *s, int(*pp)(char*))// { printf("%d: %s\n", pp(s), s);//输出s串的长度和串值 }// pp(s)的调用就是Length(s)的调用 void main() { char *x1="123456"; char *x2="asder oiu"; Out(x1, Length);//输出: 6: 123456 Out(x2, Length);//输出: 9: asder oiu } 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 六、利用函数编写程序举例 通常用一个函数,完成一个程序设计中相对独立的功能,而一个程序通常有若干个函数所组成,整个程序的功能通过函数的调用来实现。 例1:编写一个程序,判断从键盘上输入的任一个整数是否为素数。 分析:判断一个整数是否为素数的功能相对独立,可以单独编写成一个函数,该函数带有一个整数参数,假定用x表示,函数名假定用Prime表示,该函数应该把判断结果返回,所以返回类型应定义为int,当返回1时表明x是一个素数,返回0时则表明不是一个素数。 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 若一个整数是素数,则它不能被除1和本身之外的任何数整除,也就是说,若一个整数x能够分解为两个整数a和b的乘积,则它就不是素数,在这两个整数a和b中,一个若小于等于 ,则另一个必然大于等于 。所以判断一个整数x是否为素数,只要判断是否能够被2~ 中的任一数整除即可,若能够被其中的任一个数整除,则它不是素数,若不能被其中的所有数整除,则才是一个素数。 根据以上分析,编写出函数如下: int Prime(int x) { int y=(int)sqrt(x); int i; for (i=2; i<=y; i++) if (x%i==0) break; if (i>y) return 1; else return 0; } 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 在该程序的主函数中,应定义一个整型变量,假定仍用x表示,用来接收从键盘上输入的整数,接着应把x作为实参去调用求素数的函数,判断x是否为素数,然后再根据不同的判断结果输出相应的信息。带主函数的程序如下: #include<stdio.h> #include<math.h> int Prime(int x); void main(void) { int x,yn; printf("从键盘输入一个正整数:"); scanf("%d",&x); yn=Prime(x); 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 if (yn) printf("%d 是一个素数!\n",x); else printf("%d 不是一个素数! \n",x); } 若程序要求输出自然数100以内的所有素数,只要修改一下主程序即可得到。 void main(void) { int x,yn; printf("%d ",2); for (x=3; x<=99; x+=2) { yn=Prime(x); if (yn) printf("%d ",x); } printf("\n"); } 自然数100以内的所有素数: //2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 例2:编写一个函数,对一维数组a[n]中的n个整数进行排列,排列的条件是:使得数组的前面部分保存小于60的元素值,数组的后面部分保存大于和等于60的元素值。 分析:在数组的两端各设置一个位置指针i和j,开始分别指向下标0和n-1的位置,接着使前面指针i依次向后移动,直到a[i]>=60则停止,再接着使后面指针j依次向前移动,直到a[j]<60则停止,此时交换a[i]和a[j]元素的值,并分别使i和j指针向中间方向移动一个位置,然后再重复上述过程,直到i>=j为止。 例如: a[8]={23, 67, 52, 83, 75, 28, 44, 70} i↑ j↑ a[8]={23, 67, 52, 83, 75, 28, 44, 70} i↑ j↑ 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 a[8]={23, 44, 52, 83, 75, 28, 67, 70} i↑j↑ a[8]={23, 44, 52, 83, 75, 28, 67, 70} i↑j↑ a[8]={23, 44, 52, 83, 75, 28, 67, 70} i↑j↑ a[8]={23, 44, 52, 28, 75, 83, 67, 70} i,j↑ 函数定义: void TwoPart(int a[], int n) { int i=0, j=n-1; int x; while(i<j) {//进行下一遍比较和交换 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 while(a[i]<60 && i<n) i++; //条件满足时指针后移 while(a[j]>=60 && j>=0) j--; //条件满足时指针前移 if(i<j) {x=a[i]; a[i]=a[j]; a[j]=x;} //条件满足则交换 i++; j--; //指针各移一个位置 } } 主函数程序: #include<stdio.h> void TwoPart(int a[], int n); void main(void) { int i,a[8]={23,67,52,83,75,28,44,70}; 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例
C语言程序设计 TwoPart(a,8); for (i=0; i<8; i++) printf("%d ",a[i]); printf("\n"); } 输出结果:2344522875836770 总结:函数的定义、函数的调用、变量的作用域、递归函数、函数指针、应用举例。 这一讲就到这里,同学们再见! 第12讲 函数(2) 三、变量的作用域(下) 四、递归函数 五、函数指针 六、函数应用举例