Download presentation
Presentation is loading. Please wait.
1
C语言程序设计
2
项目四 简易计算器 要求: 简易计算器,完成加减乘除运算,并有界面设计。 解决问题需要的知识点: 1、函数的定义; 2、函数的调用;
项目二 项目四 简易计算器 要求: 简易计算器,完成加减乘除运算,并有界面设计。 解决问题需要的知识点: 1、函数的定义; 2、函数的调用; 3、参数的传递; 4、函数值的返回。
3
选择 结构 引例: 两个整数求和。 1
4
循环 结构 引例1:求10+8=?。
5
项目四 简易计算器 —— 第8章 函数 章节主要内容 8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用
8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用 8.4 数组作为函数参数 8.5 指针作为函数参数 8.6 嵌套调用和递归调用 8.7 存储类型 8.8 命名行参数
6
8.1 函数的基本概念 模块化程序设计 基本思想: 特点: 开发方法: 将一个大的程序按功能分割成一些小模块 自上向下,逐步分解,分而治之
各模块相对独立、功能单一、结构清晰、接口简单 控制了程序设计的复杂性 提高元件的可靠性 缩短开发周期 避免程序开发的重复劳动 易于维护和功能扩充 使每一个模块成为相对独立、功能单一、结构清晰、接口简单、容易理解的程序 每个模块可以独立设计算法,单独编写和测试 一个模块中的错误不易扩散和蔓延到其它模块, 众人可同时进行集体性开发 软件具有模块结构,软件开发工作如同搭积木,一个模块可以在不同程序中多次使用 自上向下,逐步分解,分而治之
7
…… …… …… 1、概述 C是模块化程序设计语言 C是函数式语言 必须有且只能有一个名为main的主函数
函数b 函数c …… 函数a1 函数a2 函数c1 函数c2 复杂问题 问题1 问题2 问题m …… 子问题1 子问题2 子问题n-1 子问题n …… C是函数式语言 必须有且只能有一个名为main的主函数 C程序的执行总是从main函数开始,在main中结束 函数不能嵌套定义,可以嵌套调用
8
1.函数是能够完成一个特定功能的一个独立模块
使用函数的优点: 1.函数是能够完成一个特定功能的一个独立模块 2.便于结构化程序设计采用逐步求精的方法,将一个较大的程序分解为若干个较小程序模块(即函数)来实现 3.主函数可以调用其他函数,其他函数之间也可以互相调用,减少程序书写的冗余,增强程序的可读性等
9
函数分类: 从用户角度 标准函数(库函数):由系统提供 用户自定义函数 从函数形式 无参函数 有参函数 使用库函数应注意: 1.函数功能
2.函数参数的数目和顺序,及各参数意义和类型 3.函数返回值意义和类型 4.需要使用的包含头文件
10
按函数定义分 库函数:由系统提供用户无须定义和说明就可以直接调用它们。 用户定义函数:由用户按需要编写的专门用于实现特定功能的函数。 按功能分 有返回值函数:此类被调用执行后,将向调用者返回一个函数值。 无返回值函数:此类函数用来完成特定的功能,执行完后不向调用者返回函数值。 按使用范围分 内部函数:只能在本源文件中使用。 外部函数:可在整个源程序中使用。 按数据传送分 无参函数:函数定义、函数说明及函数调用都不带参数。 有参函数:函数调用时要有参数。
11
2 、函数的定义方法 一般格式 传统风格: 合法标识符 现代风格: 函数体 函数返回值类型 缺省int型 无返回值void
函数类型说明符 函数名(形式参数表) { 说明部分 语句部分 } 现代风格: 函数体 函数类型说明符 函数名(形式参数表) 形参类型说明; { 说明部分 语句部分 } 传统风格: 函数体为空
12
项目四 简易计算器 —— 第8章 函数 章节主要内容 8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用
8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用 8.4 数组作为函数参数 8.5 指针作为函数参数 8.6 嵌套调用和递归调用 8.7 存储类型 8.8 命名行参数
13
8.2 函数参数和函数的值 1、形式参数和实际参数 形式参数:定义函数时函数名后括号中的变量。简称形参。
说明: 形参与实参顺序一致,个数相同 实参与形参的类型应相同或赋值兼容 形参在函数未被调用前不占内存。在函数调用时临时分配存储单元,调用结束释放内存 形参也是变量,在定义的函数中必须说明类型 实参可以是常量、变量和表达式,但在函数调用时要有确定的值。调用时此值赋给形参 实参变量对形参变量的数据传递是单向的值传递。实参→形参,形参→实参 1、形式参数和实际参数 形式参数:定义函数时函数名后括号中的变量。简称形参。 实际参数:在主调函数中调用一个函数时,函数名后括号中的参数。简称实参。
14
int max(int a, int b) { int c; 形 c=a>b?a:b; 参 return(c); }
void main(void) { int x,y,z; scanf("%d,%d",&x,&y); z=max(x,y); printf("Max is %d\n",z); 例:比较两个数并输出大者 形 参 z=max(x,y); /*main 函数*/ max(int a, int b)/*max 函数*/ { int c; c=a>b?a:b; return(c); } 实 参
15
2、函数的返回值 函数返值语句 形式: return(表达式); 或 return 表达式; 或 return;
例:无返回值函数 void swap(int x,int y ) { int temp; temp=x; x=y; y=temp; } 说明: 函数中可有多个return语句,但每次调用只能有一个被执行,只返回一个函数值。 若无return语句,遇最后一个}时,自动返回调用函数 若函数类型与return语句中表达式值的类型不一致,按前者为准,自动转换------函数调用转换 void型函数------无返回值函数 函数返值语句 形式: return(表达式); 或 return 表达式; 或 return; 功能:使程序控制从被调用函数返回到主调函数中,同时把返值带给主调函数
16
例:函数返回值类型转换 int max(float a, float b) { float c; c=a>b?a:b;
return(c); } void main() { float x,y; int z; scanf("%f,%f",&x,&y); z=max(x,y); printf("Max is %d\n",z);
17
项目四 简易计算器 —— 第8章 函数 章节主要内容 8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用
8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用 8.4 数组作为函数参数 8.5 指针作为函数参数 8.6 嵌套调用和递归调用 8.7 存储类型 8.8 命名行参数
18
8.3 函数的调用 说明: 1、函数调用的形式和方式 实参与形参个数相等,类型一致(或赋值兼容),按顺序一一对应 调用形式
函数名(实参表); 说明: 实参与形参个数相等,类型一致(或赋值兼容),按顺序一一对应 实参表求值顺序,因系统而定(Turbo C 自右向左) 如果调用有参函数,实参表中各参数用逗号分隔;如果调用无参函数,则实参表为空。
19
调用方式 函数语句: 例:printstar(); printf(“Hello,World!\n”); 函数表达式: 例:m=2*max(a,b); 函数参数: 例:printf(“%d”,max(a,b)); m=max(a,max(b,c));
20
2 被调函数的声明和函数原型 对被调用函数要求: 必须是已存在的函数
函数声明 一般形式:函数类型 函数名(形参类型 形参名,…… ); 或 函数类型 函数名(形参类型,……); 作用:告诉编译系统函数类型、参数个数及类型,以便检验 函数定义与函数声明不同 函数声明位置:程序的数据说明部分(函数内或外) 下列情况下,可不作函数说明 若函数返值是char或int型,系统自动按int型处理 被调用函数定义出现在主调函数之前 有些系统(如Borland C++)要求函数说明指出函数返值类型和形参类型,并且对void 和 int 型函数也要进行函数说明 对被调用函数要求: 必须是已存在的函数 库函数:#include <*.h> 或 #include "*.h" 用户自定义函数:函数声明
21
long factorial(int n);
#include <stdio.h> long sum(int a, int b); long factorial(int n); main() { int n1,n2; long a; scanf("%d,%d",&n1,&n2); a=sum(n1,n2); printf("a=%1d",a); } long sum(int a,int b) { long c1,c2; c1=factorial(a); c2=factorial(b); return(c1+c2); long factorial(int n) { long rtn=1; int i; for(i=1;i<=n;i++) rtn*=i; return(rtn); 文件包含编译预处理命令 函数原型说明 long sum(int a, int b); long factorial(int n); 形参 函数定义 实参 函数调用 函数返回值
22
printf("Max number is %d\n",z); } int max(int a, int b) { int c;
例:函数说明举例 void main() { int x,y,z; scanf("%d,%d",&x,&y); z=max(x,y); printf("Max number is %d\n",z); } int max(int a, int b) { int c; c=a>b?a:b; return(c); int max(int a, int b) { int c; c=a>=b?a:b; return(c); } void main() { int x,y,z; scanf("%d,%d",&x,&y); z=max(x,y); printf(“Max number is %d",z); 被调函数出现在主调函数 之前,不必函数说明 int型函数可不作函数说明 (Borland C++不行)
23
项目四 简易计算器 —— 第8章 函数 章节主要内容 8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用
8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用 8.4 数组作为函数参数 8.5 指针作为函数参数 8.6 嵌套调用和递归调用 8.7 存储类型 8.8 命名行参数
24
1、数组元素作函数实参——值传递(普通变量) 例:有一整型数组,判断各元素的正负,若为非负输出值为1,否则输出0。
8.4 数组作为函数参数 void judge(int); void main() { int i,x[6]; printf("Please enter 6 integers\n"); for(i=0;i<6;i++) { scanf("%d“,&x[i]); judge(x[i]); } void judge(int a) { printf("%d“,(a>=0)?1:0)); 1、数组元素作函数实参——值传递(普通变量) 例:有一整型数组,判断各元素的正负,若为非负输出值为1,否则输出0。 每输入一个数组元素的值,将该值作为实参调用一次judge函数 完成整数正负判断
25
2 、一维数组名作函数参数 实 参 形 参 指针变量int *p 数组名int q[] 数组名int x[3] 数组名a
地址传递,把实参数组名的值(即数组首地址) 传递给形参数组名,使形参和实参共占实参数组的那段内存单元 在主调函数与被调函数分别定义数组,且类型应一致 形参数组大小可不指定 形参数组名是地址变量,可定义为: *数组名 数组名[ ] 数组名[数组长度] 实 参 形 参 指针变量int *p 数组名int q[] 数组名int x[3] 数组名a 若int a[3];
26
例:输入10个学生的C语言成绩至一维数组score,编一函数求其平均成绩。
float aver(float a[ ]); void main() { float score[10];int I; for(i=0;i<10;i++) scanf("%f“,&score[i]); printf(“Average score is %5.1f“, aver(score)); } float aver(float a[10]) { int I;float sum=0.0; sum+=a[i]; return sum/10.0; 例:输入10个学生的C语言成绩至一维数组score,编一函数求其平均成绩。
27
3 、多维数组名作函数参数 地址传递,类似于一维数组 在主调函数与被调函数分别定义数组,且类型应一致
形参数组第一维的大小可省略,但第二维的大小不能省略 形参数组名是地址变量,可定义为: 若 int a[3][4]; 实 参 形 参 数组名a 数组名int x[][4] 数组名a 数组名int x[3][4]
28
例:给定一个二维数组a[3][3],求其转置
#define N 3 void main(void) { int convert(int b[N][N]); int i,j,a[N][N]; for(i=0;i<N;i++) { for(j=0;j<N;j++) { scanf("%d“,&a[i][j]); printf("%4d“,a[i][j]); } printf("\n"); } convert(a); printf("Converted array is:\n"); printf("%4d“,a[i][j]); printf("\n"); } 例:给定一个二维数组a[3][3],求其转置 int convert(int b[N][N]) { int i,j,temp; for(i=0;i<N;i++) for(j=0;j<N;j++) { temp=b[i][j]; b[i][j]=b[j][i]; b[j][i]=temp; } 调用前 调用后 调用中 a a a a[0][0] a[0][1] a[0][2] b
29
项目四 简易计算器 —— 第8章 函数 章节主要内容 8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用
8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用 8.4 数组作为函数参数 8.5 指针作为函数参数 8.6 嵌套调用和递归调用 8.7 存储类型 8.8 命名行参数
30
8.5 指针作为函数参数 传递地址值(指针)。共享内存,实现“双向”传递 例:实现两数变换。
void exchange(int x,int y) { int temp; temp=x; x=y; y=temp; } void main() { int a=4,b=5; printf("a=%d,b=%d\n“,a,b); exchange(a,b); void exchange(int *x,int *y) { int temp; temp=*x; *x=*y; *y=temp; } void main() { int a=4,b=5; printf("a=%d,b=%d\n“,a,b); exchange(&a,&b);
31
项目四 简易计算器 —— 第8章 函数 章节主要内容 8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用
8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用 8.4 数组作为函数参数 8.5 指针作为函数参数 8.6 嵌套调用和递归调用 8.7 存储类型 8.8 命名行参数
32
8.6 嵌套调用与递归调用 1 嵌套调用 嵌套调用 C规定:函数定义不可嵌套,但可以嵌套调用函数 main()函数 f1()函数
8.6 嵌套调用与递归调用 1 嵌套调用 嵌套调用 C规定:函数定义不可嵌套,但可以嵌套调用函数 main()函数 f1()函数 f2()函数 调用f1()函数; 调用f2()函数; 后继语句; 后继语句; f1()中返回语句 f2() 中返回语句 程序结束
33
③root函数调用delta函数求根的判别式。
double root(double a1,double b1,double c1) { double x1,x2,realpart,imagepart,d; d=delta(a1,b1,c1) if(a1<=1e-6 ) { printf("不是一元二次方程!"); return; } else if (fabs(d)<=1e-6) printf("有两个相等实根:%6.2f“,-b1/(2*a1)); else if(d>1e-6) { x1=(-b1+sqrt(d))/(2*a1); x2=(-b1-sqrt(d))/(2*a1); printf("x1=%6.2f,x2=%6.2f\n“,x1,x2); } else { realpart=-b1/(2*a1); imagepart=sqrt(-d)/(2*a1); printf("x1=%6.2f+%6.2fi,“,realpart,imagepart); printf("x2=%6.2f-%6.2fi“,realpart,imagepart); } } 例:用函数调用求一元二次方程的根。 要求: ①main()函数中输入a、b、c; ②调用求根root函数求方程的两个根; ③root函数调用delta函数求根的判别式。 #include "math.h" double delta(double a2,double b2,double c2) { double data; deta=b2*b2-4*a2*c2; return data; } void main() { float a,b,c; scanf("%f %f %f“,&a,&b,&c); root(a,b,c); }
34
定义:函数直接或间接的调用自身叫函数的递归调用
2 、递归调用 定义:函数直接或间接的调用自身叫函数的递归调用 int f(int x) { int y,z; …… z=f(y); ……. return(2*z); } int f1(int x) { int y,z; …… z=f2(y); ……. return(2*z); } int f2(int t) { int a,c; c=f1(a); return(3+c); f函数 f1函数 f2函数 说明 C编译系统对递归函数的自调用次数没有限制 每调用函数一次,在内存堆栈区分配空间,用于存放函数变量、返回值等信息,所以递归次数过多,可能引起堆栈溢出 调用f函数 调用f2函数 调用f1函数
35
例:用递归调用求n! #include <stdio.h> int fac(int i) { int f;
if(i<0) printf(“i<0,data error!"); else if(i==0||i==1) f=1; else f=fac(i-1)*i; return f; } void main() { int n, y; printf("Input a integer number:"); scanf("%d",&n); y=fac(n); printf("%d! =%ld",n,y); 例:用递归调用求n! (n=0) (n=1) n*(n-1)! (n>1) n!=
36
例:用函数递归调用求Fibonacci数列前20项的值。
#include "stdio.h" long fib(int n) { if (n==1) return 1; else if(n==2) else return fib(n-1)+fib(n-2); } void main() { int I; for(i=1;i<=20;i++) { if(i%4==0)printf("\n"); printf("%8ld",fib(i));} 例:用函数递归调用求Fibonacci数列前20项的值。 (n=1) (n=2) fib(n-1)+fib(n-2) (n>2) Fib(n)= 输出的结果为:
37
项目四 简易计算器 —— 第8章 函数 章节主要内容 8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用
8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用 8.4 数组作为函数参数 8.5 指针作为函数参数 8.6 嵌套调用和递归调用 8.7 存储类型 8.8 命名行参数
38
8.7 存储类型 1、变量的存储类型 变量是对程序中数据的存储空间的抽象 变量的属性 数据类型:变量所持有的数据的性质(操作属性)
存储属性: 变量在某一时刻存在,则这时属变量的“生存期”(从给变量分配内存至所分配内存被系统收回的时间间隔
39
存储器类型:寄存器、静态存储区、动态存储区
生存期:变量在某一时间存在 静态变量与动态变量 作用域:变量在某程序区域内有效 局部变量与全局变量 变量的存储类型: auto 自动型 register-----寄存器型 static 静态型 extern 外部型 变量定义格式: 存储类型 数据类型 变量表;
40
2、变量的作用域和生存期 变量的作用域是指变量在程序正文中合法出现的范围,分为局部变量和全局变量,是从空间的角度来划分的。
生存期是指变量在程序中存在的时间长短,是从时间的角度来说的。 两者有联系但不是同一回事。
41
3、内部函数和外部函数 函数在本质上是全局的,可以被其他函数调用,也可以指定不能被其他文件中的函数调用。 内部函数
概念:只能被本文件中其他函数所调用的函数。又称为静态函数。 定义格式: static 类型名 函数名(形参表) { … … } 则该函数不能被其他文件中的函数调用。这样不同的文件可以用相同名字的静态函数,而不会出错。
42
外部函数 概念:可以被其他文件中所调用的函数。 定义格式: extern 类型名 函数名(形参表) { … … } 说明: extern可以省略。 某文件要调用外部函数,需在该文件中用extern声明所调用函数(声明时也可省略extern )。 调用库函数时,只要使用#include命令指定其所在头文件,而不需要进行函数原型声明。
43
项目四 简易计算器 —— 第8章 函数 章节主要内容 8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用
8.1 函数的基本概念 8.2 函数参数和函数的值 8.3 函数的调用 8.4 数组作为函数参数 8.5 指针作为函数参数 8.6 嵌套调用和递归调用 8.7 存储类型 8.8 命名行参数
44
8.8 命令行参数 命令行参数就是指main函数的参数。虽然在前面见到的main函数后的括号是空的,但实际上main函数是可以带参数的。
一般形式: main(int argc,char *argv) 因main函数只作主调函数而不作被调函数,所以不能在程序内部取得实参值。要想取得实参值,我们从DOS操作系统命令行上给予。 可执行文件名 实参 实参 …… 说明: main函数的两个形参和命令行中的参数在个数上不是一一对应的。形参只有两个,而实参可以不止两个,其中可执行文件名也算一个参数,argc的值通常表示参数的个数,它一般由输入命令行时按输入实际参数的个数自动赋予。
45
第8章 函数——总结 内 容 总 结 函数的概念(模块化程序设计思想、函数的定义); 函数参数和函数的值(数组作为函数参数、指针作为 知
函数参数)、函数的调用(嵌套调用和递归调用); 存储类型;命名行参数。 内 容 总 结 知 识 点 函数的概念(模块化程序设计思想、函数的定义); 函数参数和函数的值(数组作为函数参数、指针作为 函数参数)、函数的调用(嵌套调用和递归调用)。 重 难 点
Similar presentations