1.04k likes | 1.2k Views
程序设计基础( C 语言). 东北大学高级语言程序设计课程组 课程网站: www.neu.edu.cn/cxsj. 程序设计基础( C 语言). 函数的基本概念. 模块化结构. 一个用 C 语言开发的软件由许多功能组成 从组成上看,各个功能模块彼此有一定的联系,功能上各自独立, 从开发过程上看,不同的模块可能由不同的程序员开发 提出模块化设计 怎样将不同的功能模块连接在一起,成为一个程序 怎样保证不同的开发者的工作既不重复,又能彼此衔接 支持这种设计方法的语言称为模块化程序设计语言. 模块化结构. C 语言提供了模块化设计的功能
E N D
程序设计基础(C语言) 东北大学高级语言程序设计课程组 课程网站:www.neu.edu.cn/cxsj
程序设计基础(C语言) 函数的基本概念
模块化结构 • 一个用C语言开发的软件由许多功能组成 • 从组成上看,各个功能模块彼此有一定的联系,功能上各自独立, • 从开发过程上看,不同的模块可能由不同的程序员开发 • 提出模块化设计 • 怎样将不同的功能模块连接在一起,成为一个程序 • 怎样保证不同的开发者的工作既不重复,又能彼此衔接 • 支持这种设计方法的语言称为模块化程序设计语言
模块化结构 • C语言提供了模块化设计的功能 • 模块化设计在程序设计中分而治之的策略 • 将一个大的程序自上向下进行功能分解成若干个子模块 • 模块对应了一个功能 • 有自己的界面 • 有相关的操作 • 完成独立的功能 • 各个模块可以分别由不同的人员编写和调试 • 将不同的模块组装成一个完整的程序 • 将所有的程序模块象积木一样装配起来
模块化结构 • C采用函数实现功能模块 • C语言中一个函数实现一个特定的功能 • 一个C语言程序可以由一个主函数和若干个其它函数构成 • 由主函数调用其它函数 • 其它函数也可以相互调用 • 同一个函数可以被一个函数或多个函数调用任意多次 • 在设计时,往往将一些常用的功能模块编写成为函数,放在函数库中,供大家选用或多次调用,以减少重复性的编写程序 • C程序的功能可以通过函数之间的调用实现 • 方便的利用函数作为程序模块实现 C语言程序设计的模块化
C程序 源程序文件1 源程序文件i 源程序文件n 预编译命令 函数1 函数n 函数首部 函数体 模块化结构 • C采用函数实现功能模块 • 一个完整的C程序可以由多个源程序文件组成 • 一个文件中可以包含多个函数
模块化结构 • C采用函数的特点 • 允许将一个程序写入不同的源文件 • 每一个源文件可以独立编译 • 一个源文件可以被不同的程序使用 • 函数是最小的功能单位 • 一个函数可以被不同的源文件的其他函数调用 • 一个源文件由多个函数组成 • 主函数可以放在任何一个源文件中 • 一个C程序只有一个主函数main( ) • 不同源文件的组装可以通过工程文件实现
模块化结构 • C采用函数的优点 • 程序设计变得简单和直观 • 提高程序的易读性和可维护性 • C语言提供了丰富的库函数 • 减少程序员的代码工作量 • 允许用户根据需要定义函数 • 提高了程序的开发速度和灵活性
什么是函数? • 什么是函数? • 函数是一段完成特定功能的程序 • 可以用简单的方法为其提供必要的数据 • 自动执行这段程序 • 能保存执行后的结果将程序回到原处继续 • 将程序中反复使用的程序定义为函数的形式
函数的种类 • 用户使用的角度 • 库函数 • 在C语言的编译系统中,提供了很多若干已经编制好的函数,用户可以直接使用 • 用户定义函数 • 用户根据需求自己编写的一段程序,实现特定的功能 • 函数的形式 • 无参函数 • 使用该函数时,不需提供数据,直接使用该程序段提供的功能,通常完成某一个处理任务 • 有参函数 • 使用该函数时,必须提供必要的数据,根据提供数据的不同,可能获得不同的结果
函数举例 例:求最大值函数 #include <stdio.h> /*函数max()的原型说明*/ int max (int x,int y); void main() {int n1,n2,n3, a; scanf(“%d%d” ,&n1,&n2,&n3); a=max(n1,n2); a=max(a,n3); printf(“最大值是%d” ,a); } /*函数max()的定义*/ int max(int x,int y) { int z ; if (x>y)z=x; else z=y; return (z); } • 说明 • 本例中共包含了两个函数 • 主函数main( ) • 用户定义函数max( ) • 主函数可以定义在程序的任意位置 • 函数的定义是平行的 • 彼此相互独立 • 不能嵌套定义 • 在主函数中 • 调用库函数 • 调用用户函数
程序设计基础(C语言) 库函数
库函数 • C语言的库函数 • 由编译系统提供的已设计好的函数,用户只需调用而无须实现 • C的库函数极大地方便了用户 • 在编写C语言程序时,应当尽可能多地使用库函数 • 提高程序的运行效率以及提高编程的质量 • 函数库 • 函数库是由系统建立的具有一定功能的函数的集合 • 库中存放函数的名称和对应的目标代码,以及连接过程中所需的重定位信息 • 用户也可以根据自己的需要建立自己的用户函数库
库函数 • 库函数 • 存放在函数库中的函数 • 库函数具有明确的功能、入口调用参数和返回值 • 头文件(又称包含文件) • C语言库函数与用户程序之间进行信息通信时要使用的数据和变量 • 在使用某一库函数时,使用#include对应该函数所在头文件 • 提示 • 不同版本的C语言具有不同的库函数 • 用户使用时应查阅有关版本的C的库函数参考手册
库函数 • 如何使用库函数? • 函数的功能及所能完成的操作 • 参数的数目和顺序,以及每个参数的意义及类型 • 返回值的意义及类型 • 需要使用的包含文件 • 要调用某个库函数,则需在程序的头部用包含命令(#include)将说明该函数原型的头文件包含进本程序中 • 例如: • include<math.h>
库函数 【例】库函数使用的例子 #include <stdio.h> #include <stdlib.h> main () { int i,j,num; for (i=0;i<10;i++) { num=rand()%10+1; for (j=0;j<num;j++) printf("*"); printf( "\n" ); } printf("\n") ; } 本例是在屏幕上输出10行*,每一行*的个数是1~20之间的随机数,程序中用到了一个可以产生随机数的库函数——rand(),这个函数的调用格式为: rand(); 调用结果返回一个随机数。库函数rand的原型说明在头文件stdlib.h中。
库函数 随机函数的应用: #include<stdlib.h> #include<stdio.h> #include<time.h> main() { int i; srand(time(NULL)); for(i=1;i<=20;i++) { printf("%10d“,1+(rand()%10)); if (i%5==0) printf("\n"); } printf("\n"); } 在随机函数时常见的错误是: 使用srand()代替rand() 函数产生随机数。
程序设计基础(C语言) 函数定义
函数的定义 • 概念 • 就是为实现某一具体功能而编写的函数的程序块 • 用户自定义函数 • 程序员自行定义和设计的函数 • 库函数一般只能提供一些低层服务的功能 • 用户自定义的函数则能针对具体的应用实现一些特殊的功能
函数的定义 • 函数定义的一般形式 • 例 函数类型 函数名(形参表说明) /*函数首部*/ { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} int max(int x,int y) { int z ; if (x>y)z=x; else z=y; return (z); }
函数的定义 函数类型 函数名(形参表说明) { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} • 函数定义的一般形式 • 说明 • 类型类型 • 规定该函数返回值的类型 • 函数返回值可以是除数组和函数外的任何合法的数据类型 • 例:int 、long、float、char、指针、结构体等 • 系统默认的类型是整类型 • 如果未指定类型,则返回值为整型 • 可用void表示如果函数没有返回值
函数的定义 函数类型 函数名(形参表说明) { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} • 函数定义的一般形式 • 说明 • 函数名 • 是用户自定义的标识符 • 是C语言函数定义中唯一不可省略的部分 • 需符合C语言命名规则的标识符 • 用在程序中标识函数,并用该标识符调用函数 • 一个好的函数名应该能够反映该函数的模块的功能 • 函数名本身代表数值 • 它代表了该函数的入口地址
函数的定义 函数类型 函数名(形参表说明) { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} • 函数定义的一般形式 • 说明 • 形参表(也称“形式参数”) • 形参表是用逗号分隔的一组变量说明 • 作用是指出每一个形参的类型和形参的名称 • 包括形参的类型和形参标识符 • 当调用函数时,接受来自主调函数的数据,确定各参数的值 • 形参表说明的两种表示形式: int func (int x, int y ){ …… } int func ( x, y )int x, y;{ …… }
函数的定义 函数类型 函数名(形参表说明) { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} • 函数定义的一般形式 • 说明 • 函数体 • 用{ }括起来的部分是函数的主体 • 函数体是一段体现函数功能的程序 • 函数内部应有自己的说明语句和执行语句 • 形式参数表中经过说明的变量可以在函数体内直接使用 • 但函数内定义的变量不可以与形参同名 • 提示 • 函数体部分可以没有,空函数,但是每个函数体外面的一对{ }不能省略 • 任何情况下不允许一个函数内部定义另外一个函数(函数不能嵌套定义)
函数的定义 函数类型 函数名(形参表说明) { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} • 函数定义的一般形式 • 说明 • 函数返回值 • 函数调用后函数体计算/执行的结果称为函数的返回值 • 通过返回语句将计算结果带回主调函数 • 函数返回值类型 • 函数定义时的类型就是函数返回值的类型 • C语言要求函数定义的类型应当与返回语句中表达式的类型保持一致 • 当两者不一致时,系统自动进行转换,将函数返回语句中表达式的类型转换为函数定义时的类型 • 提示 • 函数的类型决定着返回值的类型 • 系统进行自动的转换会造成程序的不清晰、可读性差等
函数的定义 函数类型 函数名(形参表说明) { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} • 函数定义的一般形式 • 说明 • 函数返回值 • 分析程序的运行结果 #include <stdio.h>main( ){ float a,b;int c;scanf ("%f%f", &a, &b);c = max(a,b);printf ("MAX is %d\n", c); }max ( float x, float y ){ float z;z = x>y ? x : y;return(z); } 运行时,若从键盘输入:4.5 6.8 结果为:6
函数的定义 函数类型 函数名(形参表说明) { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} • 函数定义的一般形式 • 返回语句 • 格式 • 功能 • 赋给当前被调函数一个值 • 结束当前被调函数的执行,将表达式的值带回主调函数 return 表达式; /*return(2*3)表示函数返回值为6*/return(表达式); /*return 2*3 表示函数返回值为6*/return; /*没有返回值*/
函数的定义 函数类型 函数名(形参表说明) { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} • 函数定义的一般形式 • 返回值语句 • 提示 • 函数的返回值只能有一个 • 当函数中不需要指明返回值时可以写成:return; • 并不是函数执行后没有值 • 只是没有被用户指定并由系统分配函数一个随机值 • 函数中不需要指明返回值时可以不写返回语句 • 此时,并不意味该函数不带回返回值,而是带回一个不确定的值,有可能给程序带来某种意外的影响
函数的定义 函数类型 函数名(形参表说明) { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} • 函数定义的一般形式 • 返回值语句 • 提示 • 一个函数体内可以有多个返回语句,不论执行到哪一个,函数都结束,回到主调函数 • 例如 • 对带有返回值的函数,在调用时,可以将其作为同类型的一个变量 一样使用 • 例如 sign(int x) { if(x>0) return(1); if(x==0) return(0); if(x <0) renturn(-1); } int a,b,c,max; max=max(c,max(a,b));
函数的定义 函数类型 函数名(形参表说明) { /* 函数体 */说明语句 执行语句 [ return;函数返回值]} • 函数定义的一般形式 • 返回值语句 • 提示 • 为了保证函数不返回任何值,C语言规定,可以定义无类型(void类型)函数,同时函数体可以省略使用return语句,如果使用也只能使用return;(不能带任何参数)
函数的定义 • 空类型 • 说明没有返回值 • C语言规定,一个函数可以没有返回值,函数类型应明确定义为 void(空)类型 • 对于void(空)类型函数,系统保证不使函数带有任何值 • 同时也禁止在调用函数中使用被调函数的值 • 说明没有形参 • 形参表明确地写明void,表示没有形式参数 • 例如:void main(void)
函数的定义 • 空类型 • 格式 • 说明 • void类型的函数不是调用函数之后不再返回,而是调用函数在返回时没有返回值 • void类型的函数与有返回值类型的函数在定义过程中没有区别,只是在调用时不同 • void类型的函数不能将函数调用放在表达式之中,只能在语句中单独调用 • void类型的函数一般用于完成一些规定的操作 void 函数名(形参表){ …… }
函数的定义 • 空类型 • 例题分析 • 定义为“void”型的函数,在调用时不返回任何值,所以不能将其使用在赋值语句后表达式中 • 在主调程序中引用了void函数。编系统在编译这个程序时,会提示错误信息:“not an allowed type in function main” 例: void printchar(char c) { printf(“%c=%d”,c,c); } main() {int k; k=printchar(‘a’); /* printchar没有返回值*/ printf(“%d\n” ,k); }
函数的定义 问题1: void fun1(a,b,c) { printf(“%d%d%d” ,a,b,c);}——?? 正确格式:void fun1( int a,int b,int c ) 问题2: float fun2(float a,float b) { float a,b,c; c=a+b; return(c);}——?? 形参被重复定义 问题3:已知函数abc的定义格式为: void abc() {……} 则函数定义中void的含义是____。 A.执行函数abc后,函数没有返回值 B.执行函数abc后,函数不再返回 C.执行函数abc后,可以返回任何类型 D.以上答案都是错误的
函数的定义 【例】指出如下程序段中的错误。 • int fun(void) { printf(“inside fun \n”); int fun1(void) { printf(“inside fun1\n”); } } • int sum(int x,int y) { int result; result=x+y; } (c) int sum(int x) { if(x==0) return 0; else x+sum(x-1); } 错误:函数fun1定义在函数fun的内部. 改正:将函数fun1的定义移出函数fun之外. 错误:函数应该返回一个整数值,但却没有返回值语句. 改正:添加一个return语句. return result; 或删除后 return x+y; 错误:没有返回x+sum(x-1)的结果. 改正:把else块中的语句改为: return x+sum(x-1);
函数的定义 • 无参函数的定义 • 例:编写一个函数,输出“c programming."。 #include <stdio.h>func2 ( ){ printf (“&&&&&&&&&&&&&&&\n");printf (" c programming .\n");printf (“&&&&&&&&&&&&&&&\n");}main( ){ func2( );}
函数定义小结 • C语言的程序中函数很多, main是唯一不可缺少的函数 • 是整个程序的主函数 • 程序运行时,从主函数开始执行 • 一个程序由多个函数组成时,主函数main与程序中其它函数的任意次序排列 • main作为最后一个函数放在文件结尾处,系统也总是要从main开始运行 • C语言的一个程序可以由多个文件组成 • 每个文件可以单独编译 • 将几个文件一起联接成一个可运行文件 • 一个函数的定义不能跨越在两个文件中 • 函数在一个文件中必须保持完整 • 一个程序的多个函数定义中,不允许存在相同的函数名
函数定义小结 • C语言的函数可以分为两类 • 带返回值的函数 • 通过调用可以得到一个确定的值,该值就是所调用函数的返回值 • 不带返回值函数 • 不带返回值的函数通常只是一个“过程” • 只是用来完成某种操作 • 主调函数并不需要它有任何的信息返回 • 调用时可将其作为C的一个语句直接调用 • 函数不能嵌套定义 • 一个函数的定义不能从属与另外一个函数
函数定义小结 • 无论有无形参,函数名后的()不能省略 • 形式参数表中说明的形参,在函数体中不再需要说明 • 可以同一般的变量完全一样直接使用 • 函数体内部的变量说明与形参说明的含义不同 • 前者说明函数体的一个局部变量,后者说明一个用于函数间传送数据的形式变量 • 最好在形参列表中列出每个参数的类型 • 即使参数是默认的int • 不应省略对每个形参的类型说明 • 例如: float max(float x,float y)不能写成 float max(foat x,y),此时y为系统缺省的int类型
函数定义小结 • 应尽可能多的使用系统提供的库函数 • 传递给函数的参数和函数定义中的相应的参数尽量不使用相同的名字 • 选择有意义的参数名和函数名可以使程序具有良好的可读性 • 可以避免过多地使用注释 • 需要大量参数的函数可能包含较多的功能(任务) • 应该考虑将该函数分成完成单个任务的较小的函数 • 函数原型、函数头部和函数调用应该具有一致的参数个数、参数类型、参数顺序和返回值类型
函数定义小结 • 常见错误 • 如果指定了非整型int类型的返回值类型,则省略函数定义中的返回值类型会导致语法错误 • 忘记从应该返回一个值的函数返回该值会导致无法预料的错误 • ANSI C 标准规定被省略的结果是不确定的、随机的 • 从返回类型为void的函数返回一个值会导致语法错误 • 定义函数时,在其参数列表的)后以“;”结束是一种语法错误 • 形参的类型说明一定放在函数体{}内会导致语法错误 • 在函数体内部对形式参数再次定义是一种语法错误
程序设计基础(C语言) 函数调用
函数调用 例:求最大值函数 #include <stdio.h> int max (int x,int y); void main() {int n1,n2,a; scanf(“%d%d” ,&n1,&n2); a=max(n1,n2); printf(“最大值是%d” ,a); } int max(int x,int y) { int z ; if (x>y)z=x; else z=y; return (z); } • 定义 • 一个函数调用另一个函数 • 调用者称为主调函数 • 被调用的函数称为被调函数 • 主调函数使用被调函数的功能,称为对被调函数的调用 • 函数调用的基本形式 • 通过函数名 • 函数的参数
例: int fun3() { int i,j,k; i=2; j=i*i; k=j*j; printf(“%3d%3d%3d”, i,j,k); } main() { fun3(); } 函数调用 • 函数调用方式 • 一般形式 • 函数名 (实参表)[;] • 说明 • 函数名 • 确定了被调函数的对象 • 实参表 • 函数调用时()内的变量名 • 是执行被调函数时主调函数传递给形参的实际参数 • 提示 • 参数的类型、个数和次序应与函数要求的形式参数完全统一
函数调用 • 函数调用方式 • 按照函数在主调函数中的作用,函数的调用方式有以下三种形式 • 函数语句 • 函数表达式 • 函数参数
函数调用 • 函数调用方式 • 函数语句 • 作为C程序中的一条语句调用被调函数 • 调用格式: 函数名(实参表); • 说明 • 通常只完成一种操作,不带回返回值 • 常用于调用一个可以忽略返回值或没有返回值的函数 • 只要求函数完成一定的操作
函数调用 • 函数调用方式 • 函数表达式 • 函数调用出现在一个表达式中,这个表达式称为函数表达式 • 将函数的调用结果作运算符的运算分量 • 格式 变量名=函数表达式; • 说明 • 这种方式用于调用带有返回值的函数 • 要求函数必须带回一个确定的值参与表达式的运算
函数调用 • 函数调用方式 • 函数参数 • 函数调用作为另外一个函数的实际参数 • 格式 • fun1(x,fun2); • 说明 • 这种方式要求函数必须带回一个确定的值 • 函数的参数也是表达式 • 例 m=max(max(a,b),c); 或 printf(“%d”,max(a,b));
函数声明 • 被调函数的声明 • 一个函数要调用另外一个函数 • 首先是被调用的函数必须存在 • 其次还应在主调函数中对所有被调函数加以说明 • 否则,在连接时会出现找不到所调用函数的错误信息 • 函数的调用也应遵循“先定义后使用”的原则
函数声明 • 被调函数的声明 • 库函数的声明 • 被调函数是C语言系统提供的标准库函数 • 在源程序文件的开头处,使用#include命令,将存放所调用库函数的有关“头文件”包含到该程序文件中来 • #include命令的一般形式为 • #include<math.h> • #include”stdio.h”