570 likes | 779 Views
高级语言程序设计 C. 复习. 函数的定义. 函数类型 函数名 ( 形式参数类型表 ) { 函数体 }. 说明: 函数类型指函数返回值的数据类型 函数体由语句和其它分程序组成。 形式参数可以为空,但圆括号不能省略。 函数体中不允许再嵌套定义函数 对没有返回值的函数,函数类型定为 void 型 ( 无类型或空类型 ) 。. #include "stdio.h" long fun1(int x) { int z; z=x*x; return z; } long fun2(long n) { long s=1; int i;
E N D
复习 函数的定义 函数类型 函数名(形式参数类型表) {函数体} • 说明: • 函数类型指函数返回值的数据类型 • 函数体由语句和其它分程序组成。 • 形式参数可以为空,但圆括号不能省略。 • 函数体中不允许再嵌套定义函数 • 对没有返回值的函数,函数类型定为void型(无类型或空类型)。
#include "stdio.h" long fun1(int x) { int z; z=x*x; return z; } long fun2(long n) { long s=1; int i; for(i=1;i<=n;i++) s=s*i; return s; } main() { printf("2平方!+3平方!=%ld\n",fun2(fun1(2))+fun2(fun1(3))); }
#include "stdio.h" fun(int n) { int s=0; while(n) { s=s+n%10; n=n/10; } return s; } main() { int n; printf("input n of value\n"); scanf("%d",&n); printf("result=%d\n",fun(n)); }
用自定义函数打印水仙花数共同点:立方分解出:个,十,百位上的数求它们立方和,与该数比较用自定义函数打印水仙花数共同点:立方分解出:个,十,百位上的数求它们立方和,与该数比较
fun2(int n) { int s=0,c,n1; n1=n; while(n) { c=n%10; s+=fun1(c);n=n/10; } if(s==n1) return 1; else return 0; } #include "stdio.h" fun1(int x) { return x*x*x; } main() { int m; for(m=100;m<=999;m++) if(fun2(m)) printf("%3d\n",m); }
说明: • 函数类型指函数返回值的数据类型 • 函数体由语句和其它分程序组成。 • 形式参数可以为空,但圆括号不能省略。 • 函数体中不允许再嵌套定义函数 • 对没有返回值的函数,函数类型定为void型(无类型或空类型)。 • 非void型函数 函数体中必须有return语句,形式为: return 表达式 ; 或 return (表达式) ; 用于返回函数值。表达式值的类型与函数类型最好一致。 • void型函数 函数体中return语句可以不出现。若出现,则不能带表达式。
复习 函数名(实在参数表) 形式: 函数调用的过程: • 注意: • 实参与形参的个数、位置与类型必须一致。它可以是同类型的常量、变量或表达式。 • 调用的形式可以是表达式,也可以是语句。 • 函数定义中的形参只有当发生函数调用时,才被分配内存单元。
函数调用和返回的过程: 主函数 自定义函数 ① 保存:返回地址、当前现场 ④ 输入数据 处理过程 ③ ② ⑤ 调用函数 ⑥ 函数结束或 函数值返回 ⑦ 恢复:主调程序现场、返回地址 输出 ⑧ 结束 注意:数据的输入、输出一般放在主函数中
【例5.3】求正整数m,n的最大公约数和最小公倍数 。 分析:m、n的最小公倍数为: m*n/最大公约数。 int gcd(int m,int n) //求最大公约数 {int r; while(r=m%n) {m=n;n=r;} return(n); } #include "iostream.h“ void main() { int m,n; scanf(“%d%d”,&m,&n); printf(“最大公约数%d\n”,gcd(m,n)); printf(“最小公倍数%d\n”,sct(m,n)); } int sct(int m,int n) //求最小公倍数 { return( m*n/gcd(m,n) ); } 注意: 函数中参数传递是单向“传值”。
5.1.4 函数说明(函数原型) 形式: 函数类型 函数名(形式参数类型表); 【例5.4】函数说明示例 #include “stdio.h" void main() {int a,b,c; int max(int x,int y); //函数说明,也可int max(int,int); scanf(“%d%d”,&a,&b); c=max(a,b); printf(“max=%d\n”,c); } int max(int x,int y) { return x>y?x:y ; } 省略参数名 注意: 函数调用在前,定义在后,则必须对函数进行说明,函数说明可以放在函数调用之前所在的函数内,也可以放在源文件开头、函数的外部。 函数说明和函数定义在返回类型、函数名和参数表上必须要完全一致。
练习 (1)输入正方体的长、宽、高l,w,h。求体积及三个面的面积。
#include<stdio.h> float vs( float a,float b) { return a*b; } main() { int s1,s2,s3,v,l,w,h; printf("\ninput length,width and height\n"); scanf("%d%d%d",&l,&w,&h); s1=vs(l,w);s2=vs(l,h);s3=vs(w,h);v=s1*h; printf("\nv=%d,s1=%d,s2=%d,s3=%d\n",v,s1,s2,s3); }
5.2 函数间参数传递 5.2.1 传值参数 特点:形参的改变不会影响实参的值 【例5.5】m是一个3位的正整数,将满足m、m2、m3均为回文数的正整数输出。所谓回文数是指顺读与倒读数字相同,如4、151、34543。 分析:将正整数的每位数取出,构造一个逆序的正整数,若该数与原来的相同,即为回文数。 实参:常量、变量和表达式。 形参:变量 bool palindrome(int x) { int m=x,n=0,k; while(x!=0) //构造一逆序数 { k=x%10; n=n*10+k; x/=10; } return m==n; }
【例5.6】分析下面程序,能否交换两个变量的值?【例5.6】分析下面程序,能否交换两个变量的值? #include “stdio.h" void swap(int x,int y) {int temp; temp=x;x=y;y=temp; } void main() {int a,b; scanf(“%d%d”,&a,&b); swap(a,b); printf("a=%d,b=%d\n“,a,b); }
5.2.1 引用参数 特点:形参的改变可影响实参值。 *为引用声明符。 x是a的引用, y是b的引用。 #include "stdio.h" void swap(int *x,int *y) { int temp; temp=*x;*x=*y;*y=temp; } void main() { int a,b; scanf("%d%d",&a,&b); swap(&a,&b); printf("a=%d,b=%d\n",a,b); } 形参是引用 实参只能是变量地址或数组名 引用是一种特殊类型的变量,可认为是另一个变量的别名,它不占用存储空间,对引用的操作就是对被引用者的操作,它们代表的是同一存储单元。
【例5.11】编一函数,判别一个自然数N是否是降序数,同时,求出该数各位数和。并加以调用,若是降序数输出“yes”,否则输出“no”。例如:3、441、531是降序数;而412不是降序数。【例5.11】编一函数,判别一个自然数N是否是降序数,同时,求出该数各位数和。并加以调用,若是降序数输出“yes”,否则输出“no”。例如:3、441、531是降序数;而412不是降序数。 drop(int x,int &sum) { int flag=1;int x1=x; while(x1) { sum+=x1%10;x1/=10; } while(x>=10&&flag) //判断是否降序数 if(x/10%10>=x%10) x/=10; else flag=0; return flag; }
5.2.2 数组名作参数 特点:在被调函数中对形参数组的任何改变均会影响实参所指地址里的内容 。 形参:数组名 实参:数组名或指针变量 【例5.12】对含有n个元素的整型数组a,从大到小进行排序。 void sort(int x[],int n) {int i,j,k,w; for(i=0;i<n-1;i++) {k=i; for(j=i+1;j<n;j++)if(x[k]<x[j])k=j; if(i!=k){w=x[i];x[i]=x[k];x[k]=w;} } } 数值型数组的元素个数一般须传给形参 调用:sort(a,10);
练习1#include <stdio.h> main() { int a[10],i,j,k,temp; int n=0,m=0; printf("Input 10 numbers:\n"); for(i=0;i<10;i++) scanf("%d",&a[i]); for(i=0;i<10-1;i++) /*进行n-1趟排序*/ { k=i; for(j=i+1;j<10;j++) { if(a[j]<a[k]) k=j; m++; /*统计比较的次数*/ } temp=a[i]; a[i]=a[k]; a[k]=temp; /*找到最小值,交换*/ n++; /*统计交换的次数*/ } printf("The sorted numbers:\n"); for(i=0;i<10;i++) printf("%d ",a[i]); printf("\nHave %d exchanging\n",n); printf("Have %d compare\n",m); }
#include <stdio.h> void input(int x[],int n) {int i; printf("Input n numbers:\n"); for(i=0;i<n;i++) scanf("%d",&x[i]); }
void sort(int x[],int n) {int i,j,k,temp,m=0; for(i=0;i<10-1;i++) /*进行n-1趟排序*/ { k=i; for(j=i+1;j<10;j++) { if(x[j]<x[k]) k=j; m++; /*统计比较的次数*/ } temp=x[i]; x[i]=x[k]; x[k]=temp; /*找到最小值,交换*/ n++; /*统计交换的次数*/ } }
output(int x[],int n) { int i; printf("The sorted numbers:\n"); for(i=0;i<10;i++) printf("%d ",x[i]); } main() { int a[10],i,j,k,temp; int n=0,m=0; input(a,10); sort(a,10); output(a,10); }
练习2.给定程序功能是:给一维数组a输入任意4个整数,并按下列的规律输出。例如输入1、2、3、4,程序运行后将输出以下方阵。练习2.给定程序功能是:给一维数组a输入任意4个整数,并按下列的规律输出。例如输入1、2、3、4,程序运行后将输出以下方阵。 4 1 2 33 4 1 22 3 4 11 2 3 4
#include <stdio.h> #define M 4 main() { int a[M]; int i,j,k,m; printf("Enter 4 number : "); for(i=0; i<M; i++) scanf("%d",&a[i]); printf("\n\nThe result :\n\n"); for(i=M;i>0;i--) { k=a[M-1]; for(j=M-1;j>0;j--) a[j]=a[j-1]; a[0]=k; for(m=0; m<M; m++) printf("%d ",a[m]); printf("\n"); } }
void pr1(int a[]) {int i,j,k,m; printf("\n\nThe result :\n\n"); for(i=M;i>0;i--) { k=a[M-1]; for(j=M-1;j>0;j--) a[j]=a[j-1]; a[0]=k; for(m=0; m<M; m++) printf("%d ",a[m]); printf("\n"); } } #include <stdio.h> #define M 4 void input(int a[]) { int i; printf("Enter 4 number : "); for(i=0; i<M; i++) scanf("%d",&a[i]); } main() { int a[M]; int m; input(a); pr1(a); }
【例5.13】 求字符串长度,并调用之。 int len(char s[]) { int i=0; while(s[i]!='\0')i++; return i; } 字符型数组的元素个数一般不用传给形参 调用: printf(“%d”,len(str));
正确 错误 int max(int x,int y) int max(int x,y) void sort(int a[],int n) void sort(int a[n],int n) void sort(int a[];int n) void sort(int a[],n) 注意: ① 形参和实参的类型应保持一致。 ② 函数头里的参数,要一个一个地分别说明或 列出。 下面是几种函数头正确与错误的写法: int m(int x[][4],int y) int m(int x[][],int y)
main() { int a[N]={11,32,-5,2,14},i,m=5; printf("排序前的数据:"); for(i=0;i<m;i++) printf("%d ",a[i]); printf("\n"); fun (); printf("排序后的顺序:"); for(i=0;i<m;i++) printf("%d ",a[i]); printf("\n"); } #include<stdio.h> #define N 20 void fun(int a[],int n) { int i,j,t,p; for(j=0; ;j++) { ; for(i=j; ;i++) if(a[i]>a[p]) p=i; t=a[p]; a[p]=a[j]; a[j]=t; } } }
main() { int a[N]={11,32,-5,2,14},i,m=5; printf("排序前的数据:"); for(i=0;i<m;i++) printf("%d ",a[i]); printf("\n"); fun (a,m); printf("排序后的顺序:"); for(i=0;i<m;i++) printf("%d ",a[i]); printf("\n"); } #include<stdio.h> #define N 20 void fun(int a[],int n) { int i,j,t,p; for(j=0;j<n-1;j++) { p=j; for(i=j; i<n;i++) if(a[i]>a[p]) p=i; t=a[p]; a[p]=a[j]; a[j]=t; }
main() { int n; printf("请输入1个四位的正整数:"); scanf("%d",&n); printf("该数的逆序数是:%d\n",fun(n)); } #include <stdio.h> int fun(int x) { int y=0; while (x) { y=y*10+x%10; x=x/10; } return y; }
main() { float a[20], t; int i,n; printf("Input scores:\n"); for (i=0 ;i<20; i++) { scanf("%f",&t) ; a[i]=t ;} printf("average=%f\n",); } 3、下面程序的功能是在fun函数中计算20个学生的平均成绩,返回主函数输出,请填空。 #include <stdio.h> float fun(float x[],int num) { int i; float ave,s=0; for (i=0; i<num;i++) s+=; ave=s/num; ; }
main() { float a[20], t; int i,n; printf("Input scores:\n"); for (i=0 ;i<20; i++) { scanf("%f",&t) ; a[i]=t ;} printf("average=%f\n", fun(a,20)); } #include <stdio.h> float fun(float x[],int num) { int i; float ave,s=0; for (i=0; i<num;i++) s+=x[i]; ave=s/num; return ave; }
main() { int x1,x2,x3,i=1,j,x0; printf("Input 3 number:"); scanf("%d%d%d",&x1,&x2,&x3); x0=max(x1,x2,x3); while(1) { j=; if () break; i=i+1; } printf("The is %d %d %d mingongbei is %d\n",x1,x2,x3,j); } 4、以下程序的功能是求3个数的最小公倍数。请填空。 #include <stdio.h> max(int x,int y,int z) { if () return (x); else if (y>x && y>z) return (y); else return (z); }
main() { int x1,x2,x3,i=1,j,x0; printf("Input 3 number:"); scanf("%d%d%d",&x1,&x2,&x3); x0=max(x1,x2,x3); while(1) { j=x0*i; if (j%x1==0 && j%x2==0 && j%x3==0) break; i=i+1; } printf("The is %d %d %d mingongbei is %d\n",x1,x2,x3,j); } #include <stdio.h> max(int x,int y,int z) { if (x>y&&x>z) return (x); else if (y>x && y>z) return (y); else return (z); }
5.3 递归函数 用自身的结构来描述自身就称为递归。 最典型的例子是对阶乘运算: 特点: ①原始问题可转化为解决方法相同的新问题; ②新问题的规模比原始问题小; ③新问题又可转化为解决方法相同的规模更小的新问题,直至终结条件为止。
【例5.15】编fac(n)=n! 的递归函数 递推 回归 long fac(int n) { if(n==1) return(1); return (n*fac(n-1)); } fac(3)=3*fac(2) fac(2)=2*fac(1) fac(4)=4*fac(3) fac(1)=1 fac(4)=4*6 fac(3)=3*2 fac(2)=2*1 递推过程 每调用自身,当前参数压栈,直到达到递归结束条件。 回归过程 不断从栈中弹出当前的参数,直到栈空。 思考:若fac函数中没有语句 if(n==1) return(1);程序运行结果将如何?
【例5.16】用递归函数实现将一个十进制整数转换成二至十六任意进制的字符【例5.16】用递归函数实现将一个十进制整数转换成二至十六任意进制的字符 void convert(int m,int r) { char b[17]="0123456789ABCDEF"; if(m!=0) { convert(m/r,r);cout<<b[m%r]; } } • 任何有意义的递归必须具有: • 递归结束条件及结束时的值; • 能用递归形式表示,并且递归向终止条件发展。 递归算法设计简单,程序代码简洁易读,但它消耗的机时和占据的内存空间比非递归大。
全局变量(外部变量): 在函数外部定义的变量 局部变量(内部变量): 在函数内部定义的变量, 包括形式参数 【例5.22】 5.4 作用域与存储类别 从下面三方面分析各变量 作用域(可见性): 在什么范围内可以访问 空间概念 生存期: 在什么时间存在 时间概念 初始化 #include “stdio.h" int digit(long n) { int k=0; while(n!=0) {n/=10; k+=1;} return k; } void main() { long x; scanf(“%ld”,&x); printf(“%d\n”, digit(x)); }
作用域:从定义点开始到所在的分程序结束 生存期:开始执行分程序就生成,分程序执行结束就消亡 初始化:可以初始化,缺省值为随机值。 作用域不可以扩展 5.4.1 自动变量 【例5.23】 #include “stdio.h" int f(int x) { x++; int y=5; //auto int k=5; y++; return x+y; } void main() { int k=2; printf(“%d\n”,f(k)); printf(“%d\n”,f(k+1)); } 缺省的存储类别:auto 注意:只有内部变量存储类别才能auto
5.4.2 静态局部变量 作用域:从定义点开始到所在的分程序结束。 生存期:程序的执行周期 初始化:可以初始化,缺省值为0或'\0 ' 。 初始化一次 在开始执行程序时初始化 作用域不可以扩展 一个函数可能被调用多次, 前一次调用的结果带到下一次去。 【例5.24】 #include "iostream.h" int fac(int n) {static int f=1; f=f*n; return(f);} void main() {auto int i; for(i=1;i<=5;i++) printf("i!=%d“,fac(i)); }
5.4.3 全局变量 作用域:从定义点开始到所在的文件结束 生存期:程序的整个执行周期 初始化:可以初始化,缺省值为0或'\0 '。 作用域可以扩展: 向上扩展 横向扩展,扩展到另一个文件 注意:扩展的地方不能初始化
【例5.25】外部变量示例 #include "stdio.h" int m=10; void f1(int n) { n=2*n;m=m/3; } int n; void f2() { n=5;m++;n++; } void main() { int n=2; f1(n); f2(); printf(“m=%d,n=%d\n”,m,n); } 外部变量与局部变量同名,起作用的是局部变量 注意: 外部变量的作用域只限于定义处到文件结束,定义点之前的函数或其它文件中的函数不可以引用该外部变量。 可以使用extern声明符来扩展外部变量的作用域
(1)作用域向定义点之前的函数扩展 #include <stdio.h> extern int i; //不能初始化 void fun() { // extern int i; printf(“i=%d\n”,i); } int i=5; void main() { int j=20; printf(“j=%d\n”,j); fun(); } #include < stdio.h> extern int i; void fun() { //extern int i; 错误 printf(“i=%d\n”,i);} void g() {i++;} int i=5; void main() { int j=20; printf(“j=%d\n”,j); g(); fun(); }
(2)作用域扩展到另一个文件 【例5.26】作用域横向扩展示例 //file1.cpp extern max,min; #include " stdio.h.h" void main() { void maxmin(int x[],int n); int a[10]={11,2,3,-4,5,6,7,8,0,20}; maxmin(a,10); printf(“%d,%d\n”,max,min); } //file2.cpp int max,min; void maxmin(int x[],int n) { max=x[0];min=x[0]; for(int i=0;i<n;i++) { if(x[i]>max)max=x[i]; if(x[i]<min)min=x[i]; } }
一句话 可以有若干个窗口(参数), 门only one(返回值为一个),多个返回值依赖于数组名作参数或全局变量.
5.5 程序举例 【例5.27】编一判断质数的函数,验证歌德巴赫猜想:任何大于2的偶数均可表示为两个素数的和。例如:4=2+2(特例,仅此一个),6=3+3,8=3+5,…。程序要求输入任一偶数,输出6到该数范围内的各个满足条件的组合。 分析:对一个偶数,分解为两个质数和,既n=a+b。方法是从找最小的质数a为3开始(因2是偶数,另一个必定是偶数,不可能是质数),判断b=n-a是否是质数,若b也是质数,则n符合要求;否则,找下一个质数a,再判断b。