380 likes | 492 Vues
第 5 章 函数. 输入 2 个正整数 m 和 n, 计算 m! + n!. #include <stdio.h> void main( ) { int I,m,n; double fm,fn; scanf("%d%d", &m, &n); fm=1; for(i=1;i<=m;i=i+1) fm=fm*i; fn=1; for(i=1;i<=n;i=i+1) fn=fn*i; printf("%f<br>",fm+fn); }. 求 m! 、 n! 同做一过程. m!. f=1;
E N D
第5章 函数 输入2个正整数m和n,计算 m!+n! #include <stdio.h> void main( ) { int I,m,n; double fm,fn; scanf("%d%d", &m, &n); fm=1; for(i=1;i<=m;i=i+1) fm=fm*i; fn=1; for(i=1;i<=n;i=i+1) fn=fn*i; printf("%f\n",fm+fn); } 求m!、n! 同做一过程 m! f=1; for(i=1;i<=k;i=i+1) f=f*i; n! 用函数做 当k=m; m!=fact(m) 当k=n; n!=fact(n)
5.1.1 程序解析 计算m!+n!,用函数求解 #include <stdio.h> double fact(int n);/*函数声明*/ void main( ) { int m,n;scanf("%d%d",&m,&n); printf("%f\n",fact(m)+fact(n)); } double fact(int n) /* 定义求 n! 的函数*/ {int i; double result=1; for (i=1;i<=n;i++) result=result*i; return result;/* 把结果回送主函数 */ } 主函数 其它函数 C程序由一个主函数或一个主函数与若干其它函数构成
5.1.2 函数定义 函数:完成一个特定工作的独立程序模块 函数分为:库函数,由C语言系统提供。如:scanf()、printf() 自定义函数,用户自己编写。如:求阶乘函数fact() 1. 函数定义格式 ⑴返回函数值的函数定义 函数首部 格式型标识符 函数名(形式参数表) { 说明语句 执行语句 return 表达式; } 函数体 其中 函数名自定义,按标识符规定命名 形式参数表定义该函数计算依赖的参数和参数类型 类型标识符int、float、double 、char函数返回值的类型 说明语句用于说明语句里用到各数据变量的类型 执行部分各种计算语句 return 表达式;计算函数返回值
例 编写求n!的函数 函数名 形式参数表 函数首部 double fact(int n) {int i; double result=1; for (i=1;i<=n;i++) result=result*i; return result; } 函数类型 函数体 说明语句 执行语句 函数返回值
⑵不返回函数值的函数定义 格式void 函数名(形式参数表) { 说明语句 执行语句 return; /* 可省略 */ } 函数首部 函数体 函数返回类型 其中 void空类型,表示函数无返回值 void pyramid(int n) { int i,j; for(i=1;i<=n;i++) {for(j=1;j<=n-i;j++) printf(" "); for(j=1;j<=i;j++) printf("%d ",i); putchar('\n'); } } 例5-2输出数字金字塔 #include <stdio.h> void main( ) { void pyramid(int n); pyramid(5); }
⑶类型标识符缺省 函数返回值为整型 #include <stdio.h> main( ) { printf("%d\n", fact(5)); } fact(int n) {int i,result=1; for (i=1;i<=n;i++) result=result*i; return result; } 格式 函数名(形式参数表) { 说明语句 执行语句 return 表达式; } 注:源程序文件 .c方式适合。 源程序文件 .cpp方式不适合。
主函数的几种不同表示 void main() {.... } main() {.... } int main() {.... return 0; }
2. 函数参数表 定义函数的自变量,函数计算的已知数据 例 编写求n!的函数。 已知 n 计算函数n! double fact(int n) n是函数的参数,称形式参数或简称形参 函数参数表定义方式 ⑴方式1类型标识符 函数名(形式参数表) { 函数体 } 形式参数表格式: 类型1 参数1 ,类型2 参数2,…,类型n 参数n ⑵方式2类型标识符 函数名(形式参数名表) 形式参数类型说明 { 函数体 } 形式参数名表:参数1,参数2,…, 参数n 形式参数类型说明:类型1 参数1,参数2,…, 参数n;类型2 …;
例 对浮点数x和整数n,编写求xn 的函数。 形式参数名表 形式参数表 double expon(x,n) float x;int n; {double y;int i; y=1; for(i=0;i<n;i++) y=y*x; return y; } double expon(float x,int n) {double y;int i; y=1; for(i=0;i<n;i++) y=y*x; return y; } 形参类型说明 注:源程序文件 .c两种形参定义方式均可。 源程序文件 .cpp只适合第一种方式。 两种定义方式书写不要混淆。 如第一种方式定义: int x,int y,float z 不能写成 int x,y,float z
3. 函数返回值 函数返回值 通常函数经过计算得到一个函数值 如 fact(3) 得到 6 6是函数返回值 函数返回值需要使用return语句实现 格式return(表达式); 或 return 表达式; 操作 一执行return,先计算表达式,然后中断函数返回函数调用处 表达式值作为函数返回值 double fact(int n) {int i; double result=1; for (i=1;i<=n;i++) result=result*i; return result;/* 把结果回送主函数 */ }
注在函数体内return语句个数不限 例5-3定义函数even(n),当n为偶数时返回1,否则返回0 int even(int n) {if(n%2==0) return 1; else return 0; } 当return(表达式)中表达式的值与函数类型不一致,强行转换成函数类型 return只能返回一个数值, 如 return x,y; 只能返回y int fact(int n) {int i; double result=1; for (i=1;i<=n;i++) result=result*i; return result; } 当函数体内无return语句,函数体执 行完毕返回随机值(void函数除外)
5.1.3 函数的调用 例5-2 #include <stdio.h> void main( ) { void pyramid(int n); pyramid(5); } void pyramid(int n) { int i,j; for(i=1;i<=n;i++) {for(j=1;j<=n-i;j++) printf(" "); for(j=1;j<=i;j++) printf("%d ",i); putchar('\n'); } } 函数调用:使用函数 1. 函数调用的方法 ⑴函数语句 格式 函数名(实参表列); 一般用于函数无返回值
⑵作为表达式中的一个元素 格式 函数名(实参表列) 例 计算12! void main() {int i, n; double s; scanf("%d",&n); s=fact(n); printf("s=%f\n",s); } double fact(int n) {int i;double result=1; for (i=1;i<=n;i++) result=result*i; return result; }
2. 函数参数的传递 参数传递:形参与实参结合 形式参数指函数定义时形式参数表中的参数 实际参数指调用函数时在参数表位置上出现的参数 形参 double expon(float x,int n) {double y;int i; y=1; for(i=0;i<n;i++) y=y*x; return y; } 例 void main() {int a;double t; scanf("%lf,%d",&t,&a); t=expon(t,a); printf("%f\n",t); } 实参 虚实结合 形参与实参的个数、位置、类型一致 个数 形参的个数与实参的个数相同 位置 形参实参依次按排列位置相结合 类型数据类型和参数形式相对应
类型 一致 数据类型相对应 形参实参 整型 整型 实型 实型 字符 字符 但字符与整型互通 参数形式 形参 实参 变量 常量、变量、表达式 数组 数组、指针 指针 指针、数组 如 double expon(float x,int n) expon(3.5,a+3) 上面讲的形参与实参结合是语法要求,其数据是怎么结合的?
当形参是变量,虚实结合是单向值传递,即实参赋值于形参当形参是变量,虚实结合是单向值传递,即实参赋值于形参 如函数定义 double expon(float x,int n) 函数调用expon(t,a) 则 t=>x a=>n 计算expon(x,n)后 t,a值不变 例 编写交换两个变量值的函数swap() void main() {int a=1,b=2; swap(a,b); printf("a=%d,b=%d\n",&a,&b); } void swap(int x,int y) {int t; t=x;x=y;y=t; } 运行结果: a=1,b=2 不能交换 形参、实参可用指针实现双向值传递 void main() {int a=1,b=2; swap(&a,&b); printf("a=%d,b=%d\n",&a,&b); } void swap(int *x,int *y) {int t; t=*x;*x=*y;*y=t; } 运行结果: a=2,b=1 交换
3. 函数执行过程 (1)分配函数的内存单元 (2)虚实结合 (3)执行函数体 (4)函数结束或遇到return返回函数调用处 (5)收回分配函数的内存单元 double expon(float x,int n) {double y;int i; y=1; for(i=0;i<n;i++) y=y*x; return y; } 例 void main() {int a;double t; scanf("%lf,%d",&t,&a); t=expon(t,a); printf("%f\n",t); }
4. 被调用函数的声明 ⑴使用库函数需要头文件中说明 格式 #include <库文件名.h> 或 "库文件名.h" 如 #include "stdio.h" #include "math.h" ⑵使用自定义函数需要在调用函数的模块中声明被调用函数 格式 类型标识符 被调用函数名(形参说明表); 或 类型标识符 被调用函数名(); 注:源程序文件 .c两种形参定义方式均可。 源程序文件 .cpp只适合第一种方式。
函数调用说明 函数调用说明 例 #include <stdio.h> void main( ) {double fact(); printf("%f\n",fact(12)/(fact(5)+fact(7))); } double fact(int n) {int i; double result=1; for (i=1;i<=n;i++) result=result*i; return result; } #include <stdio.h> void main( ) {double fact(int n); printf("%f\n",fact(12)/(fact(5)+fact(7))); } double fact(int n) {int i; double result=1; for (i=1;i<=n;i++) result=result*i; return result; }
注 允许缺省被调用函数说明,满足下述条件之一 定义的被调用函数出现在调用语句的模块之前 #include <stdio.h> double fact(int n) {int i; double result=1; for (i=1;i<=n;i++) result=result*i; return result; } void main( ) { printf("%f\n",fact(12)/(fact(5)+fact(7))); } fact函数 主函数 调用函数
被调用的函数类型是int类型说明 #include <stdio.h> main( ) { printf("%d\n", fact(5)); } int fact(int n) {int i, result; result=1; for (i=1;i<=n;i++) result=result*i; return result; } 调用函数 注 仅源程序文件 .c可以。
在源程序文件的开始说明被调用函数,即在函数的外部说明在源程序文件的开始说明被调用函数,即在函数的外部说明 #include <stdio.h> double fact(int n); void main( ) { printf("%f\n",fact(12)/(fact(5)+fact(7))); } double fact(int n) {int i; double result=1; for (i=1;i<=n;i++) result=result*i; return result; } 函数的外部说明 调用函数 主函数 fact函数
函数的结构 形式参数表 函数返回值 函数的类型 函数的调用 函数参数的虚实结合 函数执行过程 函数被调用的说明
函数参数的虚实结合 函数定义 例 对浮点数x和整数n,编写求xn 的函数。 #include <stdio.h> void main() {double expon(float x,int n); int n;float x;double s; scanf("%f,%d",&x,&n); s=expon(x,n); printf("%lf\n",s); } 函数被调用的说明 函数执行过程 (1)分配函数的内存单元 float y,int m; double z;int i; (2)虚实结合 x->y,n->m (3)执行函数体 (4)函数返回return z; 返回函数调用处 (5)收回分配函数的内存单元 float y,int m; double z;int i; 函数的调用 函数的类型 形式参数表 double expon(float y,int m) {double z;int i; z=1; for(i=0,;i<m;i++) z=z*y; return z; } 函数返回值
5.2 使用函数编写程序 #include <stdio.h> #include <math.h> void main( ) { printf("pi=%f\n",pi); } 求 例5-4按 要求定义和调用函数funpi(double e) 实现。e为计算精度 double funpi(double e); double e,pi; scanf("%lf",&e); pi=funpi(e); #include <stdio.h> #include <math.h> void main( ) { int i,flag; double item,pi; pi=0;flag=1;i=1;item=1; while(fabs(item)>=1e-5) {pi=pi+item; i=i+1;flag=-flag; item=flag*1.0/(2*i-1); } pi=pi*4; printf("pi=%f\n",pi); } double funpi(double e) {int i,flag; double item,pi; pi=0;flag=1;i=1;item=1; while(fabs(item)>=e) {pi=pi+item; i=i+1;flag=-flag; item=flag*1.0/(2*i-1); } pi=pi*4; return pi; }
n= i=2,n,1 1 m%i==0 0 i 0 i≥n+1 1 返回0 返回1 例5-5求100之内的全部素数,1不是素数,2是素数。要求定义和调用函数prime(m)判断m是否为素数,当m为素数返回1,否则返回0 #include "stdio.h" #include "math.h" int prime(int m) { } int i,n; if(m==1) return 0; n=sqrt(m); for(i=2;i<=n;i++) if(m%i==0) break; if(i>=n+1) return 1; else return 0; if(m%i==0) return 0; return 1; void main( ) {int m; for(m=1;m<=100;m++) if(prime(m)) printf("%d ",m); }
5.3 变量与函数 本节讨论变量的作用域以及与函数的关系 5.3.1局部变量和全局变量 1.局部变量 局部变量函数内部定义的变量,在本函数范围内有效 如程序 float f1(a) int a; {int b,c; …... } char f2(x,y) int x,y; {int i,j; …... } void main() {int m,n; ……. } a,b,c 有效域 m,n 有效域 x,y,i,j 有效域
注(1)在主函数中定义的变量仅在主函数内有效 (2)函数的形参是局部变量 (3)复合语句中定义的变量作用域只在复合语句内部 例5-6 void main() {int a; a=1; {int b=2; b=a+b; a=a+b; } printf("%d ",a); } b有效域 (4)不同函数中可以定义相同名字的变量,但代表的是不同对象 分配不同的存储单元
2.全局变量 全局变量在函数外部定义的变量,其有效域为从定义变量的位置起到 本源程序文件结束。 int p=1,q=5; float f1(a) int a; {int b,c;... } char c1,c2; char f2(x,y) int x,y; {int i,j; } main() {int m,n; … } 如源程序文件 全局变量 p,q 有效域 c1,c2 有效域
注(1)当全局变量与局部变量同名时,在局部变量的有效域内全局注(1)当全局变量与局部变量同名时,在局部变量的有效域内全局 变量不起作用。 例 int a=1,b=5; int max(int a,int b) {int c; c=a>b?a:b; return(c); } main() {int a=8; printf("%d\n",max(a,b)); } 全局变量 局部变量 a,b 有效域 全局变量 a,b有效域 减去局部变量同名的 有效域 局部变量 局部变量 a 有效域 输出 8 (2)全局变量的缺省值(初值)为0
注(3)利用全局变量进行函数之间数据传递 例 王婆卖瓜:要求每卖一次瓜要记下个数与重量,以统计所卖出瓜的总个数与总重量。另外需要说明的是,王婆允许退瓜。 void main() {char c;float wt;int num; while(1) {switch(c=getchar()) {case 'b':scanf("%d",&num); scanf("%f",&wt); back(num,wt);break; case 's':scanf("%d",&num); scanf("%f",&wt); sale(num,wt);break; case 'q':exit(0);} c=getchar(); printf("%d ", all_number); printf("%f\n", all_weight);}} #include <stdio.h> float all_weight; int all_number; void sale(int number,float weight) {all_number+=number; all_weight+=weight; } void back(int number,float weight) {all_number-=number; all_weight-=weight; } 全局变量 总重量、总个数 利用全局变量传递
全局变量进行函数之间数据传递运算速度快,但一般不采用,原因是全局变量进行函数之间数据传递运算速度快,但一般不采用,原因是 (1)函数通用性不好,移植困难 (2)程序可读性差 (3)调试程序不方便 当函数有多个返回值可使用数组或指针 void sale(int number,float weight,int *all_number,float *all_weight) {*all_number+=number; *all_weight+=weight; } void back(int number,float weight, int *all_number,float *all_weight) {*all_number-=number; *all_weight-=weight; }
5.3.2动态存储变量和静态存储变量 变量从作用域的角度来分,分为局部变量和全局变量 从生存时间角度来分,分为静态存储变量和动态存储变量 静态存储程序运行期间分配固定存储空间的方式 动态存储程序运行期间根据需要进行动态分配存储空间的方式 静态存储还是动态存储由变量的存储类别决定 存储类别分为四种 自动的 auto 、静态的 static 、寄存器的 register 、外部的 extern 格式存储类别关键字 类型关键字 标识符1,标识符2,...; 如 auto int a,b,c;
1. auto存储类 函数中的局部变量,凡不加存储类说明的都表示为auto类,即auto 可以缺省。如 int f(a) int a; {int b,c=3; ...} int f(a) auto int a; {auto int b,c=3; ...} 注auto类属于动态存储, 进入函数分配存储单元,退出函数系统收回存储单元
2.static存储类 static声明的变量属于静态存储,其用途让局部变量在退出它所在函数后仍保留存储单元,下一次进入该函数后,这些局部变量的值仍有效。称为静态局部变量。 例5-8阅读程序 运算 #include<stdio.h> void fun(int k) {int a=0; printf("%d, ",a); a=a+k; } void main() {int k; for(k=1;k<=3;k++) fun(k); } k a 输出 a+=k 1 0 0 0+1-->1 2 0 0 0+2-->2 3 0 0 0+3-->3 输出0, 0, 0,
例5-9阅读程序 运算 #include<stdio.h> void fun(int k) {static int a=0; printf("%d, ",a); a=a+k; } void main() {int k; for(k=1;k<=3;k++) fun(k); } k a 输出 a+=k 1 0 0 0+1-->1 2 1 1 1+2-->3 3 3 3 3+2-->5 输出0, 1, 3, 注:static型与auto型区别 存储单元分配: static分配固定存储空间 auto动态分配存储空间 存储单元缺省值:static为0 auto为随机值
3. register存储类 直接使用寄存器存储数据,提高运算速度,属于动态存储 例 阅读程序 一般小型机16个寄存器允 许3个作为register变量 个人微机13个寄存器没有 多余寄存器作为register变量 当定义的register变量超过 能使用的寄存器时自动转成 auto类变量。 #include<stdio.h> void fun(int k) {register int a=0; printf("%d, ",a); a+=k; } void main() {int k; for(k=1;k<=3;k++) fun(k); } 输出 0, 0, 0,
4. extern 变量 格式 extern [类型名] 变量名表; extern只是说明变量起作用,告诉C编译器该变量后面会定义。它不分配存储单元,所对应存储单元在变量定义处分配。 #include<stdio.h> void main() {int a; extern x; a=1; x=a; x=x+a; printf("%d\n",x); } int x; 声明x变量,在后定义 定义x是全局变量