C语言项目开发教程PPT精选文档

上传人:s9****2 文档编号:568289487 上传时间:2024-07-24 格式:PPT 页数:93 大小:302.50KB
返回 下载 相关 举报
C语言项目开发教程PPT精选文档_第1页
第1页 / 共93页
C语言项目开发教程PPT精选文档_第2页
第2页 / 共93页
C语言项目开发教程PPT精选文档_第3页
第3页 / 共93页
C语言项目开发教程PPT精选文档_第4页
第4页 / 共93页
C语言项目开发教程PPT精选文档_第5页
第5页 / 共93页
点击查看更多>>
资源描述

《C语言项目开发教程PPT精选文档》由会员分享,可在线阅读,更多相关《C语言项目开发教程PPT精选文档(93页珍藏版)》请在金锄头文库上搜索。

1、第第4章章 函函 数数在大型程序中,一个同样的程序段可能需要出现多次,这样,程序将变得十分冗长,一旦这部分程序需要调整,程序的修改工作将十分繁重。因此,C语言中提供了函数方式,利用这种方式,可以将一个复杂的问题分解为很多小问题,给每一个小问题编写一段程序(函数体),为这段程序设定名称(函数名)以及接收数据的方式(参数)。最后把很多个这样的函数通过函数调用组合成一个完成复杂功能的有机体。这就是C语言结构化设计的思想。通过这种结构化的设计,将复杂的程序任务分解为很多个更小、更简单的任务。每一个任务由一个函数完成,而函数中的变量和代码也独立于程序的其他部分,这样使得程序编写更容易。同时如果程序中有错

2、误,可以将问题缩小到特定的函数,使程序更加容易调试。C语言中的函数有两种:标准函数和自定义函数。前者由系统提供,如之前用到的printf()、puts(),数据处理函数sin(x)、cos(x)等,这类函数只要把其对应的头文件包括进来即可以直接调用;后者是程序员根据需要自己定义的函数。本章主要讨论自定义函数的使用方法。1任务4.1 数学能力测试系统任务目标了解函数的功能和优点。掌握函数的定义形式。掌握函数的调用方法。掌握形参和实参的概念。掌握函数说明语句的形式和用法。掌握函数的值的概念。掌握函数返回值的用法。完成数学能力测试程序设计。24.1.1 函数的定义函数定义就是确定函数完成什么功能以及

3、如何运行的程序模块。函数必须先定义,然后才能使用。创建一个函数时,必须指定函数头作为定义的第一行,接着是这个函数放在一对大括号内的执行代码。这些代码成为函数体。函数头指明了函数的返回值类型、函数的名称和参数,函数体完成函数所有的处理操作。函数定义的一般形式为:类型标志符 函数名(形式参数表) 变量说明 执行语句其中,类型标志符即函数类型,函数类型和函数返回值的类型一致,如果没有返回值,则函数类型为void。有的函数有返回值,有的函数没有返回值。函数的返回值是指函数被调用之后,执行函数体中的程序段所取得的并返回给主调用函数的值。有返回值的参数,其函数体中必须有相应的返回语句return。函数名是

4、唯一标识一个函数的名称,应为一个合法的标识符。形式参数列表由0个、1个或多个参数组成。参数之间用逗号隔开,每个参数都包括参数的类型和名称。例如int max(int a,int b);中声明了两个参数,它们均为int类型。用大括号括起来的部分为函数体,包括变量说明和执行语句,这一部分的代码表明了函数可以实现的功能。函数体内可以没有代码,但是大括号必须存在。空的函数体在调试大型程序时经常用到。出现在形式参数列表中的形参,以及出现在函数体变量说明中的变量都是局部变量,只在函数内部生效。3下面是合法的函数定义的例子。【案例4-1】 输出简单图形。void print() int i,j; for(i

5、=1;i=10;i+) for(j=1;j=i;j+) printf(*); printf(n); 案例4-1中定义了一个void类型的无参数函数print,该函数的功能为在屏幕上打印一个10行的三角形。当函数没有返回值时,必须说明函数类型为void,这里的void不可以省略。【案例4-2】 根据参数输出简单图形。void print(int x) int i,j; for(i=1;i=x;i+) for(j=1;j=i;j+) printf(*); printf(n); 案例4-2中定义的函数print包含一个参数,其功能同样为在屏幕上打印一个三角形,不同的是三角形的行数是由函数的参数确定的

6、。函数运行前首先接收通过函数调用传递的参数,确定x的取值,然后执行后续操作。4下面几个关于函数定义的案例是不正确的。【案例4-3】 定义函数,根据输入的参数输出一个长方形。void print(int x, y) int i,j; for(i=1;i=x;i+) for(j=1;j=y;j+) if(i=1|j=1|i=x|j=y) printf(* ); else printf( ); printf(n); 在函数定义中,每一个形参都必须用一个类型说明符单独说明,不可以公用。将上述案例中的函数定义改为void print(int x,int y),则函数定义正确。【案例4-4】 定义一个函数

7、,输出一个数的平方。void add(int x,int y) int result; void squart(int x); result=suqart(x)+squart(y) printf(%d,result);案例4-4中,在一个函数的函数体内又定义了另外一个函数,这种现象为函数的定义嵌套,这是不正确的。5在C语言中,所有的函数定义,包括main()函数在内,都是平行的,也就是说一个函数的函数体内,不能定义另一个函数,即不能嵌套定义。是函数之间运行互相调用时,也允许嵌套调用,但main()函数除外,main()只能调用其他函数而不能被调用。因此,C程序的执行总是从main()函数开始,

8、完成对其他函数的调用后再返回到mian()函数,最后由mian()函数结束整个程序。一个程序有且只能有一个mian()函数。64.1.2 函数的调用 1函数调用形式程序中之所以定义函数,是为了在程序中其他需要的地方调用函数。在程序中是通过对函数的调用来执行函数体的。在前面的章节中,其实已经涉及到了一些函数的调用的案例,如printf函数、puts函数等的调用。函数调用时通过函数调用语句实现的,主函数就是主调函数,主函数中调用的函数为被调函数。函数调用的一般形式为:函数名(实际参数表)对无参数函数调用时无实际参数。实际参数列表中的参数可以是常数,变量或其他构造类型数据表达式,各参数之间用逗号隔开

9、。这里的参数的个数、类型和顺序都应与被调函数定义中的参数列表中的设置相同。函数调用的过程为:先计算出实际参数表中各表达式的值,然后把值传递给对应的形参,然后再将执行控制流转向被调函数的第一个语句并执行函数体。当函数执行完后,执行控制流返回到主调函数中。函数调用的结果称为函数的值,也就是函数体中return 语句返回的值。可通过“函数名(实际参数表)”的形式访问返回语句返回的值,如,有以下函数:int add(int a,int b) return a+b;其中,return语句表示返回a加b的值,即调用该函数可获得a加b的值,调用形式为add(a,b)。函数调用有三种表现形式,分别为:作为单独

10、的函数调用语句;作为函数的部分参数;作为表达式的一部分。7【案例4-5】 编写程序,求三个数中的最大值。#include int max(int a,int b,int c) if(ab) if(ac) return a; else return c; else if(bc) return b; else return c; void main() int a,b,c; int maxnum; printf(请依次输入三个整数:n); scanf(%d%d%d,&a,&b,&c); printf(最大值为:%dn,max(a,b,c); /函数调用作为输出参数8程序运行结果如下:请依次输入三个

11、整数:9 2 6最大值为:9案例中定义了求三个数中的最大值函数max,函数中通过比较返回三个参数中的最大值。在主程序中,函数调用作为输出参数直接输出。可以将上述程序中的输出部分提取出来单独作为一个函数,则程序可变为:void print(int maxnum) printf(最大值为:%dn,maxnum);void main() int a,b,c; int maxnum; printf(请依次输入三个整数:n); scanf(%d%d%d,&a,&b,&c); print(max(a,b,c);此时对print函数的调用是作为单独的函数调用语句,函数没有返回值,只是完成独立的操作。max函

12、数的调用结果则作为参数传递给print函数。9 2函数的形参和实参在函数定义中,出现在函数名括号中的参数为形式参数,简称形参;函数调用时,出现在函数名后括号中的参数是实际参数,简称实参。函数调用时,形参的数量和类型要和实参的数量和类型相一致,并且实参和形参的顺序也应保持一致,所代表的意义也一致。形参和实参的功能是数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参,从而实现主调函数向被调函数的数据传送。形参和实参的使用有以下特点:(1)形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该

13、形参变量。 (2)实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值、输入等办法使实参获得确定值。 (3)实参和形参在数量上、类型上、顺序上应严格一致,否则会发生“类型不匹配”的错误。 (4)函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此,在函数调用过程中,形参的值发生改变,而实参中的值不会变化。10【案例4-6】 计算从1到n的和。#include int s(int n) int i; for(i=n-1;i=1;i-) n=n+i; pri

14、ntf(函数s中: n=%dn,n); return 0;void main() int n; printf(请输入一个正整数:n); scanf(%d,&n); printf(主函数中调用s前:n=%dn,n); s(n); printf(主函数中调用s后:n=%dn,n);程序运行结果如下:请输入一个正整数:100主函数中调用s前:n=100函数s中: n=5050主函数中调用s后:n=10011本程序中定义了一个函数s,该函数的功能是求ni的值。在主函数中输入n值,并作为实参,在调用时传送给s函数的形参量n(注意,本例的形参变量和实参变量的标识符都为n,但这是两个不同的量,各自的作用域不

15、同)。在主函数中调用函数s前用printf语句输出一次n值,这个n值是实参n的值。在函数s中也用printf语句输出了一次n值,这个n值是形参最后取得的n值,然后再在主函数中输出一次n的值,发现n的值仍为10不变。从运行情况看,输入n值为100。即实参n的值为100。把此值传给函数s时,形参n的初值也为100,在执行函数过程中,形参n的值变为5050。返回主函数之后,输出实参n的值仍为100。可见传值调用时实参不随形参的变化而变化。在函数调用时,为形参变量n分配内存单元,并将实参n的值传递给形参n。然后在函数s内对n的值进行计算,形参n的值发生了变化。在程序结束时,要释放为形参n分配的内存空间

16、。即形参n只在函数s内部有效,函数s的执行不会影响主函数中实参s的值,函数调用前后实参值不变。123函数的说明C语言可以由若干个文件组成,每一个文件又可以单独编译,因此当编译程序中的函数调用时,如果不知道该函数参数的个数和类型,编译系统就无法检查形参和实参是否匹配。为了保证函数调用时,编译程序能够检查出调用过程中传递的参数和函数定义中的参数是否类型一致和个数匹配,以保证函数调用的成功,因此有时在主调用函数中需要对调用函数进行说明。在之前的例子中,总是先写调用函数然后再写主调函数。但是实际上组成一个程序的函数的位置是任意的,即有可能主调函数在被调函数之前,此时需要用到函数说明语句,否则将无法使用

17、被调函数。函数说明的一般形式如下:函数类型 函数名(形式参数列表)例如:int max(int a,int b);13【案例4-7】 求圆的面积。#include #define PI 3.14void main() float x; float a; float area(float x); printf(请输入圆的半径:n); scanf(%f,&x); a=area(x); printf(圆的面积为:%.3fn,a);float area(float x) float a; a=PI*x*x; return a;程序运行结果如下:请输入圆的半径:6圆的面积为:113.04014函数的说明

18、除了在主调函数中,也可以出现在函数的外部,如上述程序可以改写为:#include #define PI 3.14float area(float x);void main() float x; float a; printf(请输入圆的半径:n); scanf(%f,&x); a=area(x); printf(圆的面积为:%.3fn,a);float area(float x) float a; a=PI*x*x; return a;函数的说明和函数定义在形式上类似,但是函数说明并不等价于函数定义。函数的定义由两部分组成:函数首部和函数体,函数的定义中应包括实现函数功能的语句和返回值等;而函

19、数的说明中只是一个说明,没有具体的功能实现语句。15另外,函数的定义只能有一次,而函数的说明可以有多次,每次调用函数之前就应该在主调函数中说明依次。例如:#define PI 3.14void main() float area(float x); void print() float area(float x); float area(float x) float a; a=PI*x*x; return a;在主函数和另外一个函数print中均用到了函数area,所以都在调用前对函数area进行了说明,但是函数area的定义只有一次,在定义中给出了函数的具体功能的实现。而函数的说明则不包括功

20、能实现。函数说明并不是必须的,在下列情况中不需要对函数进行说明也可以使用:函数返回值为整型或字符型时,且在同一个文件中既定义函数,又调用函数;函数的定义和调用在同一个文件中,且定义在调用之前。如果函数的定义和调用在两个不同的文件中,则无论函数返回值的类型是什么,在调用函数时,必须给出函数的说明。16【案例4-8】 求长方形的面积。#include void main() int x,y; int a; printf(请输入长方形两边长:n); scanf(%d%d,&x,&y); a=area(x,y); printf(长方形的面积为:%dn,a);int area(int x,int y)

21、int a; a=x*y; return a;程序运行结果如下:请输入长方形两边长:5 6长方形的面积为:30174.1.3 函数的值函数的值指示函数调用之后,执行函数体中的程序段所取得并返回给主调用函数的值,函数值的类型为函数类型。函数的值只能通过返回值的形式返回给主调用用函数。返回值语句return的形式如下:return 表达式;执行时,首先计算表达式的值(可以为常量表达式、变量或复合类型的表达式),然后将该值返回给调用函数。函数类型一般与return 语句表达式的类型一致。如果函数不提供返回值,则可以定义函数类型为空类型(void)。如果return 语句中表达式的类型与函数的类型不一

22、致,则以函数的类型为准,返回时自动进行数据类型转换。一个程序中可以有多个return语句,但是每次调用只能执行一个return语句,因此函数只能有一个返回值。如果函数不提供返回值,且被定义为空类型时,系统默认函数类型为整型。返回值语句return 的作用为:结束本函数运行,返回到主调用函数中执行下一条指定;将表达式运算结果返回到调用处。18【案例4-9】 编写一个函数,在屏幕上显示一个字符串。#includevoid print() char s100; printf(请输入一个字符串:n); gets(s); printf(输入的字符串为:n); puts(s); return;void m

23、ain() print(); printf(输出结束n);程序运行结果如下:请输入一个字符串:Hello输入的字符串为:Hello输出结束19程序中定义了一个无参数函数print(),在执行完最后一个语句puts(s),即显示字符串s 之后,遇到return语句,函数结束并返回到主调用函数中,即继续执行主函数中的输出语句。在函数类型为void的情况下,通常可以省略return语句的使用,函数执行完最后一条语句后,自动结束并返回到主调用函数中20【案例4-10】 编写一个函数,比较a、b的大小,并返回其中较大的一个。#include int max1(int a,int b) if(a=b) r

24、eturn a; else return b;int max2(int a,int b)Return (ab?a:b);void main() int a,b; int m; printf(请输入两个整数:n); scanf(%d%d,&a,&b); printf(两个数中较大值为:n); m=max1(a,b); printf(调用函数max1运行结果:%dn,m); m=max2(a,b); printf(调用函数max2运行结果:%dn,m);21程序运行结果如下:请输入两个整数:10 15两个数中较大值为:调用函数max1运行结果:15调用函数max2运行结果:15在这个程序中定义的函

25、数max1和max2的功能为返回两个数中的较大值。在这个两个函数中,程序并不是执行到最后一条语句之后才终止并跳出到主程序中的,而是根据比较结果,如已知ab时,则不需要执行下面的else语句就可以确定最大值,这时可以直接跳出函数。程序max1和max2的功能均为比较两个数的最大值,max2函数中只有一条return语句,max1中有两条return语句,但函数具体执行时都只执行其中的一条return语句,返回该函数值到主调用函数中。函数的返回值非空时,则可以将函数的值看成一个明确的数值用在任意表达式中,如将函数返回值赋给另外的变量或直接输出函数返回值。注意,用户定义的函数大部分属于以下三种类型:

26、第一种为数据处理型,函数的主体为对数据进行计算或其他处理,最后输出数据处理结果;第二种为信息处理型,对一些信息进行处理,处理后返回一个值,这个值仅作为处理成功或失败的标记,而无具体的含义;第三种为功能独立型,完成指定的功能,没有返回值。224.1.4 任务实现1问题描述编写程序,训练儿童加、减、乘、除数学算数能力的程序。程序应该能自动生成加法、减法、乘法和除法运算的算数表达式,并且通过学生输入的答案判断结果是否正确,然后给出提示。在用户选择结束程序时,可以统计共回答了多少题,得分为多少。2要点解析根据程序功能,可以将总程序分为5个模块,即add:随机输出加法表达式并判断答案是否正确。sub:随

27、机输出减法表达式并判断答案是否正确。mul:随机输出乘法表达式并判断答案是否正确。divi:随机输出除法表达式并判断答案是否正确。mark:统计答题数目和得分情况。233程序实现#include#include#includevoid add();void sub();void mul();void divi();void mark(int c);int count = 0,sum = 0;void main() int choice; char ans = y; printf(欢迎使用儿童算数运算能力测试程序nn 长时间使用计算机不利于儿童身体健康nn 每次只能做一项练习:nn); prin

28、tf(t1.加法运算n); printf(t2.减法运算n); printf(t3.乘法运算n); printf(t4.除法法运算n); printf(t0.退出n); printf(请选择操作(0-4):); scanf(%d,&choice);24 while(ans = y | ans = Y) switch(choice) case 1:add();break; case 2:sub();break; case 3:mul();break; case 4:divi();break; case 0:printf(欢迎下次使用,再见!nn);exit(0); default:printf(

29、输入有误!nn);exit(0); printf(是否继续?按y继续,按n退出。n); scanf(%s,&ans); mark(choice);void add() int x,y,z,result; srand(time(NULL); x = rand()%10; y = rand()%10; result = x + y; printf(%d+%d= ,x,y); scanf(%d,&z); if(z = result) printf(恭喜你,答对了,加10分!nn);25 sum+=10; else printf(答错了,继续努力哦!nn); count+;void sub() int

30、 x,y,z,result; srand(time(NULL); x = rand()%10; y = rand()%10; result = x - y; printf(%d-%d= ,x,y); scanf(%d,&z); if(z = result) printf(恭喜你,答对了,加10分!nn); sum+=10; else printf(答错了,继续努力哦!nn); count+;26void mul() int x,y,z,result; srand(time(NULL); x = rand()%10; y = rand()%10; result = x * y; printf(%

31、d*%d= ,x,y); scanf(%d,&z); if(z = result) printf(恭喜你,答对了,加10分!nn); sum+=10; else printf(答错了,继续努力哦!nn); count+;void divi() int x,y,z,result; srand(time(NULL); x = rand()%10; y = rand()%10;27 while(x%y != 0 | y = 0) srand(time(NULL); x = rand()%10; y = rand()%10; result = x / y; printf(%d/%d= ,x,y); s

32、canf(%d,&z); if(z = result) printf(恭喜你,答对了,加10分!nn); sum+=10; else printf(答错了,继续努力哦!nn); count+;void mark(int c) switch(c) case 1:printf(本次共做加法题%d道,总得分为%d!n,count,sum);break; case 2:printf(本次共做减法题%d道,总得分为%d!n,count,sum);break; case 3:printf(本次共做乘法题%d道,总得分为%d!n,count,sum);break; case 4:printf(本次共做除法题

33、%d道,总得分为%d!n,count,sum);break; printf(欢迎下次使用,再见!n);28程序运行结果如下:欢迎使用儿童算数运算能力测试程序长时间使用计算机不利于儿童身体健康每次只能做一项练习: 1.加法运算 2.减法运算 3.乘法运算 4.除法运算 0.退出请选择操作(04):19+8= 17恭喜你,答对了,加10分!是否继续?按y继续,按n退出。y2+5= 7恭喜你,答对了,加10分!是否继续?按y继续,按n退出。y5+1= 6恭喜你,答对了,加10分!是否继续?按y继续,按n退出。y4+8= 10答错了,继续努力哦!是否继续?按y继续,按n退出。n本次共做加法题4道,总得

34、分为30!欢迎下次使用,再见!29任务4.2 汉诺塔问题 任务目标掌握函数的递归调用方法。掌握函数嵌套调用方法。掌握变量局部变量和全局变量的概念和用法。掌握变量的静态和动态存储方式。掌握全局变量和局部变量的存储方式。完成汉诺塔程序设计304.2.1 嵌套调用和递归调用 1函数的嵌套调用在C 语言中,各函数的定义是平等的,独立的,不允许在一个函数的函数体内定义另外一个函数,即函数的定义不允许嵌套。但是C 语言中,运行在一个函数的定义中会出现另外一个函数的调用,即函数的嵌套调用。当出现这样的调用时,在执行第一个函数的函数体过程中会出现第二个函数的调用和执行。【案例4-11】 函数的嵌套调用。#in

35、clude void fun1() void fun2(); printf(-n); fun2(); printf(-n);void fun2() printf(*n);void main() void fun1(); void fun2(); printf(&n); fun1(); printf(&n);31程序运行结果如下:&-*-&其中,函数的执行过程为:(1)执行main函数的开头部分。(2)遇到fun1函数的调用语句,转向fun1函数的执行。(3)执行fun1的开头部分。(4)遇到fun2函数的调用语句,转向fun2函数的执行。(5)执行fun2函数。(6)fun2函数执行结束,返回

36、其调用处,即fun1。(7)继续执行fun1函数。(8)fun1函数执行结束,返回到main函数的执行。(9)main函数执行结束,程序终止。32程序执行流程如图4-1所示。 图4-1 嵌套函数执行流程 2函数的递归调用在调用一个函数的过程中又出现了直接或间接地调用该函数自身,这种函数调用方式称为递归调用33例如:void fun() fun(); 在函数体内直接有本函数的调用,这种方式为直接递归调用。void fun1() fun2(); void fun2() fun1()在一个函数的函数体内调用了另外一个函数,但是该函数又有对本函数的调用,这种方式为嵌套递归调用。由于算法的有穷性特点,不

37、能让一个函数无休止地调用其函数自身,这样会导致死循环。因此,必须采用某些手段来终止递归调用,常用的方法是在递归调用前添加判断条件,条件不满足之后就跳出该递归调用。【案例4-12】 使用递归调用求一个数的阶乘。设定f(n)=n!,则可知f(n-1)=nf(n-1),f(1)=1,f(0)=1。34源程序如下:#include int f(int n) int s; if(n0) printf(输入错误!n); return 0; if(n=0|n=1) s=1; else s=f(n-1)*n; return s;void main() int n; int s; printf(请输入一个正整数

38、:); scanf(%d,&n); s=f(n); printf(%d!=%dn,n,s);程序运行结果如下:请输入一个正整数:55!=12035主函数调用scanf函数得到一个正整数,然后调用f函数,并且f中n的值为5,此时n的值不满足n0或者n=0|n=1,所以继续调用函数f。第二次调用f时,形参n接收到的实参值为4,然后继续调用,直到第五次调用,接收到的形参值为1,满足条件n=1,则执行s=1,然后执行return语句。这样第4次调用f收到第5次调用的返回值f(1),并计算f(2)=2f(1)=2,并将这个值返回给第3次调用,第4次调用结束;第3次调用根据第4次调用的返回值f(2)计算f

39、(3)3f(2)=6,结束本次调用并返回给第2次调用;第2次调用计算f(4)=4f(3)=24;第一次调用计算f(5)=5f(4)=120,然后返回给主程序并输出。案例4-12也可以不用递归的方法,而是直接使用循环语句来实现,且比递归法更加易于理解和容易实现。但是有些问题则比较适合用递归法来实现,比如:(1)可以将问题转化为与原问题解决方法相同的新问题,通常新问题的规模和复杂度较原问题递减。(2)简化之后的问题是易于实现的或者已知解决方法的。(3)递归必须有一个出口,即终止递归语句的条件。36【案例4-13】 输入一个正整数序列,以相反的顺序输出该序列,以递归的方法实现。将原问题分解为解决方法

40、相同的几个小问题:假设输出的正整数只有一位,则问题简化为反向输出一位正整数。这样只要输出这一位正整数即可。对于一个位数大于1的正整数,则可以将其在逻辑上分为两部分:个位数的数字和个位数之前的所有数字。则问题分解为:(1)先输出个位数的反向序列。(2)再输出其他部分的反向序列。显然前面一个问题是已经可以解决的,问题转化为输出个位数之前的反向序列。对于个位数之前的数字,可以继续按上述规则将其分解,直到完成整个正整数序列的反向输出。37程序源代码如下:#include void change(int num) int n=num; if(n=0&n=9) /若n为一位整数 printf(%d,n);

41、 /直接输出 else printf(%d,n%10); /输出n的个位数 change(n/10); /输出n的个位数之外的其他数字 void main() int num; printf(请输入一个正整数序列:n); scanf(%d,&num); printf(该整数的反向序列为:n); change(num); printf(n);程序运行结果如下:请输入一个正整数序列:123456789该整数的反向序列为:987654321上述问题的解决方案为将问题进行分解,然后用较小的问题来解决较大的问题,即递归的思想。384.2.2 局部变量和全局变量在C语言中,变量的不同定义形式和定义位置,使

42、得变量有不同的有效范围,这个有效范围即变量的作用域。从变量的作用域来划分,变量可以分为局部变量和全局变量。 1局部变量局部变量也称内部变量,是指在函数内定义的变量。局部变量的作用域仅限于本函数内,即只能在本函数中使用,在函数执行结束后即释放该变量的内存空间,离开函数之后再使用这种变量是非法的。局部变量的形式有以下三种。(1)在函数体内定义的变量:其作用范围只能在所处的函数内,一旦超出这个范围,变量不起作用。(2)在函数形式参数列表中定义的变量:其作用范围只在函数内部。(3)在符合语句中定义的变量:其作用范围仅在所处的复合语句中。39例如:int f1(int i) int j,k; int f

43、2(int x) int y,z; 函数f1中定义了三个变量,i为形参,j和k为变量,i、j、k仅在f1内部有效,或者i、j、k的作用域仅限于f1内部。同理,f2中定义的x、y、z的作用域f2内部,仅在f2内部有效。允许在不同函数中使用相同的变量名和形参名。复合语句中也可以定义变量,其作用域只在复合语句范围内,如:void fun() - int x,y; - x和y的作用域 int z; z的作用域 z=x+y; - -同一函数体内或同一层的复合语句内,应先进行所有的声明,然后再写执行语句。不同层的复合语句,变量之前可以重名。此时执行到内层语句时,同名变量中内层定义的变量有限,外层变量被屏蔽

44、,结束内层语句后才有效40【案例4-14】 局部变量的作用域。#include int add(int x,int y) int sum; sum=x+y; return sum;int plu(int x,int y) return x-y;void main() int x=3; int y=3; printf(x=%d,y=%dn,x,y); int x=5; printf(x=%dn,x); y+; printf(x=%d,y=%dn,x,y); printf(x+y=%dn,add(x,y); printf(x-y=%dn,plu(x,y);程序运行结果如下:x=3,y=3x=5x=

45、3,y=4x+y=7x-y=-1请读者自行分析上述程序中各个变量的作用域41 2全局变量在任何函数体外定义的变量为全局变量。全局变量的作用域比较宽,它的有效范围为从其定义的位置开始到所在源文件的结束,在这个区域内任意函数都可以调用它。例如:int a,b; /外部变量void fun1() int x,y;void fun2() void main() 其中a、b、x和y都是外部变量,a和b的作用域为从其开始定义到fun1、fun2和main函数,而x和y的定义在fun1之后,所以其作用域为fun2和main函数。全局变量可以加强函数模块之间的数据联系,但是会使函数之间的独立性降低,这在程序模

46、块化设计的观点看是不利的。全局变量的使用还容易导致程序错误,因为全局变量为多个函数共享,因此全局变量的错误将会传递给其作用域所在的所有函数。因此在程序设计时应尽量避免全局变量的使用,加强函数的独立性。在同一个源文件中,允许全局变量和局部变量同名。在局部变量的作用范围之内,全部变量被屏蔽,不起作用。例如:42int x=0;void fun(int x) x=x+1;Void main() fun(x); printf(x=%d,x);程序中定义了一个全局变量x,它的作用范围为从定义到文本结束。而fun函数中也定义了一个同名的变量x,则在fun内部,全局变量x不起作用。程序执行时,调用函数fun

47、(x),这里的 x为全局变量,即x=0。程序转向fun函数时,fun函数内的x被赋值为0,并执行x=x+1的操作,局部变量x变为1。函数fun执行结束之后,继续执行main函数,输出x的值。此时fun函数中改变的x的值为局部变量x,全局变量x的值不变,输出结果应为x=1。43【案例4-15】 全局变量的使用。#include int max,min,avg;void process(int num) int score,sum=0; int count=0; printf(请输入学生%d的成绩:n,num); scanf(%d,&score); max=min=score; do sum=su

48、m+score; if(scoremax) max=score; count+; scanf(%d,&score); while(score=0); avg=sum/count;void main() int i; for(i=1;i=3;i+) process(i); printf(*学生1*n); printf(最高分t最低分t平均分n); printf(%dt%dt%dn,max,min,avg); 44程序运行结果如下:请输入学生1的成绩:78 90 86 74 92 -1*学生1*最高分 最低分 平均分92 74 84请输入学生2的成绩:89 93 82 85 71 -1*学生1*最

49、高分 最低分 平均分93 71 84请输入学生3的成绩:78 92 94 65 99 -1*学生1*最高分 最低分 平均分99 65 85454.2.3 变量的存储类型C语言中的每一个变量都有两个属性:变量类型和存储类型。变量的作用域从变量在什么空间内有效的角度划分,可以分为全局变量和局部变量。变量的存储类别则是以变量在内存中存在的时间角度划分的,可以分为动态存储方式和静态存储方式两种。静态存储方式是指在程序运行期间分配固定的存储空间的方式。而动态存储方式则是在程序运行期间根据需要动态分配存储空间的方式。编译后的C程序有4个不同的逻辑内存区域,它们分别有不同的功能。程序区:用来存放程序代码的区

50、域。静态存储区:用来存储程序中的全局变量和局部变量。栈区:程序运行时用来存放临时数据,可以用来保存函数调用时的现场和返回地址,也可以用来存放形式参数变量和自动局部变量等。堆区:是一个自由存储区域,程序通过C语言的动态存储分配函数来使用它,用于存储链表等。栈和堆的内容是动态变化的,因此也称为动态存储区。数据可以存放在动态存储区和静态存储区,变量的存储相应地可以分为动态存储类型和静态存储类型。由于全局变量可以供程序中所有函数使用,所以全局变量的值需要在整个运行期间进行保存,全部变量应该安排在静态存储区内。局部变量可以放在静态存储区内,也可以放在栈区。一个变量属于静态存储还是动态存储,并不能仅从其作

51、用域来看,还应该考虑其存储类别说明。46在C语言中,变量的存储类别如表4-1所示。表4-1 变量存储类别auto自动变量动态存储方式register寄存器变量extern 外部变量静态存储方式static静态变量下面详细介绍上述4种存储类别。 1auto自动变量auto的变量类型为动态存储变量,其一般形式为:auto 数据类型 变量名;例如:auto int a;函数中的变量如果不做特殊说明,系统都是动态地分配内存空间,数据存储在动态存储区中,函数的形参和在函数中定义的变量都属于此类。在调用变量时系统为其分配内存空间,在函数调用结束后自动释放内存空间,这类变量为自动变量。auto只能用来说明函

52、数体内的局部变量,不能说明形参、全局变量。函数中的形参虽然不用auto来说明,但是形参也是auto类型变量。函数被调用运行期是该函数自动局部变量的生存期。自动局部变量的有限生存期可以节省内存单元,而且使函数独立性增强。变量类型为auto时,auto也可以省略,省略是默认为auto类型。47 2registerregister定义的变量值存放在CPU的寄存器中,而不像普通的变量存储在内存单元中。使用寄存器来存储变量的速度比使用普通变量快得多,这时因为寄存器变量实际上存储在CPU中,不需访问内存来确定和修改其值。存储其变量的定义形式为:register 数据类型 变量名;例如:register i

53、nt a;寄存器变量可以提高数据的读取速度,以提高程序的运行效率。不过,有的编译系统可以忽略寄存器存储类型修饰符,直接把register变量当成自动变量处理,在内存中给其分配内存单元,而不把数据放在存储器中;并且现在计算机的运行速度越来越快,性能越来越高,优化的编译器能够自动识别使用比较频繁的变量,将其放在寄存器中,而不需要程序员的指定。因此,register类型的变量在实际应用中使用不多,这里只要了解即可。48 3externextern 类型说明符可以用来扩展外部变量的作用域。在不加任何说明的情况下,声明全局变量的作用域只能从定义开始,到变量所在的文件结束为止,如果要把作用范围扩展到其他文

54、件或文件的其他区域,则需要定义外部变量,即extern 类型的变量。extern 类型的变量定义形式为:extern 变量名;【案例4-16】 外部变量的使用。在同一个工程中创建两个文件,分别命名为file1和file2。file1的代码:#include int a;void main() int power(int n); int b=3,c,d,m; scanf(%d,%d,&a,&m); c=a*b; printf(%d*%d=%dn,a,b,c); d=power(m); printf(%d%d=%dn,a,m,d);file2的代码:extern a;int power(int n

55、) int i,y=1; for(i=1;i=n;i+) y*=a; return y;49程序运行结果如下:2,32*3=623=8案例4-16在file1中定义了变量a,变量a的作用域为整个file1文件。文件file2中使用extern a声明将a的作用域又扩展到了file2中。这样a在file2中同样有效。程序先通过接收键盘输入将a的值赋为2,然后调用power函数,power函数中有对a进行处理的语句,语句中a的值也为2。同理,函数也可以使用外部声明扩展作用范围,如案例4-16也使用了外部函数power,外部函数的声明可以省略关键字extern504static类型static 有以

56、下两个作用。(1)把未用auto 说明的局部变量的存储方式由动态存储方式改为静态存储方式,即改变其生存周期。前面介绍到,如果一个局部变量定义为auto 类型或者未说明类型,则默认为动态存储方式存储,函数调用时为其分配内存空间,函数结束后自动消失。但是如果函数的局部变量声明为static 类型,则该变量即变为静态存储类型,称为静态局部变量,该变量是在变量定义时就分配内存空间,并且一直存在,直到整个程序执行结束。静态局部变量的作用域仍和动态局部变量相同,即只能在定义该变量的函数内使用,退出该函数之后,尽管该变量还继续存在,但是不能使用。如果再次调用该函数,则可以继续使用该变量,并且保留上次调用该函

57、数结束时该变量的值。如果一个变量声明为static 类型,且在定义时未给其赋初值,则系统自动为其赋初使值为0。51【案例4-17】 静态局部变量和动态局部变量的比较。#include int fun1() int x=0; x+; return x;int fun2() static int y=0; y+; return y;void main() int i; printf(fun1:t); for(i=0;i5;i+) printf(%dt,fun1(); printf(n); printf(fun2:t); for(i=0;i5;i+) printf(%dt,fun2(); print

58、f(n);52程序运行结果为:fun1: 1 1 1 1 1fun2: 1 2 3 4 5fun1和fun2中分别定义了一个静态局部变量和动态局部变量,比较函数fun1和函数fun2的5次运行结果可以看出,每次fun1运行时,fun1的返回值不变,这时因为每次fun1运行开始时为x 分别存储空间并赋初值,fun1运行结束后就释放内存空间,所以每次运行x 的值不变;而fun2中y 为静态局部变量,编辑时即分配内存空间并赋初值,每次运行fun2时y 的值保持为上次fun2运行结束时y 的值,所以连续5次运行fun2时返回的值分别为1、2、3、4、5。(2)使全局变量的作用域无法扩展到其他文件中。前

59、面介绍过使用extern可以将一个文件中的全局变量扩展到其他文件中,但是为了保成程序的独立性,并不希望一个文件中定义的变量可以让其他文件任意使用,这样就可以使用static来完成,即在定义一个变量时加上static修饰符,那么该变量就只能在当前文件中使用。【案例4-18】 用static改变全局变量作用域。file 中代码如下:#include void a();void b();void main() extern int num; num=7; a(); b();53file1中代码如下:#include int num;void a() printf(file1:%dn,num);fil

60、e2中代码如下:#include static int num;void b() printf(file2:%dn,num);程序运行结果如下:file1:7file2:0从上述案例中可以看出,file 使用extern 引用外部变量只能引用file1中的全局变量,而不能引用file2中的静态全局变量。static 在不同地方的作用不同,使用的时候应该注意544.2.4 任务实现1问题描述汉诺塔游戏来自印度的一个古老传说,开天辟地的神波拉玛在一个庙里留下了3根金刚柱,第一根上面套着大小不同的64个金片,上小下达依次排列。游戏的目标是将所有的金片搬到第三个柱子上,搬移过程中,可以利用中间的柱子作

61、为辅助,但是一次只能搬移一个金片,搬移下来之后只能放到三个柱子中的一个上,且大的不能放在小的上面。要解决的问题为:有3根柱子A、B、C。A 柱上有若干按大小顺序叠放的金片。每次移动一个金片,且只能移到A、B、C中任一根柱子上,大的不能叠放在小的之上。把所有的金片从A 柱移动到C 柱上。试编写程序模拟搬移过程。552要点解析可以根据递归的思想来分析这个问题。如果只有一个金片,则把金片从A移动到C上即可,移动结束。如果有n个金片,则将前n-1个金片移动到B上,然后将最后一个金片移动到C上,最后将前n-1个金片从B移动到C上即可。将前n-1个金片从A上移动到B上又可以分为三个过程:将前n-2个金片移

62、动到A上,再将第n-1个金片移动到C上,最后将前n-1个金片移动到C上即可。同理将前n-1个金片从B移动到C的过程类似。依次进行这样的分解,最后完成整个搬移任务。程序设计如下:(1)如果n=1,则将金片从A上移动到C上。(2)如果n=2,将n-1(即第一个)个金片移动到B上,然后将第n个金片移动到C上,最后将前n-1个金片移动到C上。(3)如果n2时,先将前n-1个金片移动到B上,然后将第n个金片移动到C上,最后将前n-1个金片移动到C上即可。每次将n个金片从原始柱子移到另外一个目标柱子时,都先将前n-1个金片移动到第三个柱子上,然后移动第n个柱子,最后将前n-1个柱子从第三根移动到目标柱子上

63、563程序实现/汉诺塔程序#include int num=0;/hanio程序,第一个参数表示金片的数量/后面三个参数分别代表金片开始所在的柱子、需要借用的第三根柱子、目标柱子void hanio(int n,char A,char B,char C) if(n=1) printf(将金片%d从%c移动到%cn,n,A,C); num+; else hanio(n-1,A,C,B); printf(将金片%d从%c移动到%cn,n,A,C); num+; hanio(n-1,B,A,C); void main() int n; void hanio(int n,char a,char b,c

64、har c); printf(请输入金片的数量:); scanf(%d,&n); hanio(n,A,B,C); printf(完成目标,共需移动%d次n,num);57程序运行结果如下:请输入金片的数量:4将金片1从A移动到B将金片2从A移动到C将金片1从B移动到C将金片3从A移动到B将金片1从C移动到A将金片2从C移动到B将金片1从A移动到B将金片4从A移动到C将金片1从B移动到C将金片2从B移动到A将金片1从C移动到A将金片3从B移动到C将金片1从A移动到B将金片2从A移动到C将金片1从B移动到C完成目标,共需移动15次58任务4.3 学生信息管理系统之函数实现 任务目标掌握数组在函数中

65、的用法,比较使用数组作为函数的参数和返回值与使用基本数据类型时的区别。了解一些常用的库函数,掌握库函数的使用方法。掌握编译预处理的知识。用函数实现学生信息管理系统程序。4.3.1 数组和函数在函数中,参数可以是表达式,数组元素和变量可以作为表达式的组成部分,所以数组元素也可以作为函数的参数。数组元素可以作为函数实参,其用法和基本数据类型变量相同,另外,数组名也可以作为实参和形参,传递的是数组的首地址。 1数组元素作为函数参数数组元素作为函数的参数和变量作为函数参数时一样使用,传递的是数值,是“值传递”方式,接收的实参值和形参应是具有相同类型的变量。59【案例4-19】 一个数组中有10个数,比

66、较其中的最大值。#include void main() int max(int a,int b); int a10; int i,m; printf(输入10个正整数:n); for(i=0;i10;i+) scanf(%d,&ai); m=a0; for(i=1;ib) return a; else return b;程序运行结果如下:输入10个正整数:8 29 13 6 32 21 17 0 19 20最大值为:32602一维数组作为函数参数一维数组作为函数参数,可将数组名作为函数实参。数组名作为函数实参时,形参可以是数组或者指针变量,关于指针的使用在后面章节中会进行介绍,现在只讨论形参

67、和实参都是数组时的情况。数组名作为实参时,实参向形参传递的不是具体的值,而是数组的首地址,函数将实参的地址传递给形参,形参和实参共用同一块内存单元,形参值的改变会影响实参的值,这种参数传递方式为“传地址”。数组作为形参时可以不指明数组的大小,只在数组名后面加一个方括号表示形参类型为数组,有时为了程序需要,可以另外设置一个参数表示数组长度,用来传递需要处理的数组中元素的个数。函数调用需要数组作为实参时,直接将数组名作为参数即可,不需要指明数字的长度,也不需要加方括号。61【案例4-20】 数组元素排序。#include void sort(int a,int n) int i,j,tmp; fo

68、r(i=0;in-1;i+) for(j=0;jaj+1) tmp=aj; aj=aj+1; aj+1=tmp; void main() int a10; int i; printf(输入10个正整数:n); for(i=0;i10;i+) scanf(%d,&ai); sort(a,10); printf(排序后数组为:n); for(i=0;i10;i+) printf(%d ,ai); printf(n);62程序运行结果如下:输入10个正整数:13 36 82 74 53 96 87 9 3 18排序后数组为:3 9 13 18 36 53 74 82 87 96 通过案例可以看出,在

69、传值调用时,将实参的值赋给形参,函数改变或使用形参的值,实参的值不变;而传地址时,将实参的地址传递给形参,实参和形参公用内存单元,形参值的改变即实参值的改变,函数调用结束后实参值为函数结束时的形参值。 3二维数组作为函数参数可以用二维数组作为函数的参数。二维数组作为实参时,可以直接使用二维数组名。二维数组作为形参时,可以指定每一维的大小,也可以省略第一维的大小说明,但是不能省略第二维的大小说明。同样,函数调用的时候只要以二维数组名作为实参即可,不需要指明数组的长度,也不需要方括号。63【案例4-21】 有一个43的矩阵,求其中元素的最小值。#include int min(int a3) in

70、t i,j,m; m=a00; for(i=0;i4;i+) for(j=0;j3;j+) if(aijm) m=aij; return m;void main() int array43=9,8,7,7,6,5,6,5,4,4,3,2; printf(最小值为:%dn,min(array);程序运行结果为:最小值为:2644.3.2 库函数在C 语言中,有很多已经定义好并存在某一个文件中,供用户直接使用,这就是库函数。最常用的printf、scanf 函数都是库函数。使用库函数时要用include 命令,引用库函数所在的文件名,其一般形式为:#include 文件名 或#include 例如

71、printf和scanf函数所在的文件为stdio.h,应在使用前在程序开头添加#include 命令。常用的库函数有:int abs(int x); /求整数的绝对值double exp(double x); /求指数函数double log(double x); /求对数函数double sin(double x); /求正弦值double cos(double x); /求余弦值double pow(double x,double y); /指数函数,求x的y次方double sqrt(double x); /求平方根void rand();/随机数生成void gettime(stru

72、ct time timep); /获取当前系统时间65【案例4-22】 库函数的使用。#include #include #include #include #include void main() int x,y,s; struct time t; gettime(&t); printf(当前系统时间为:%2d:%02d:%02dn,t.ti_hour,t.ti_min,t.ti_sec); srand(time(NULL); x = rand()%10; y=rand()%10; s=pow(x,y); printf(%d的%d次方为%dn,x,y,s);程序运行结果如下:当前系统时间为:

73、10:05:346的7次方为279936664.3.3 编译预处理编译预处理是在对源程序证时编译之前的处理。用#开头的命令就是预处理命令。在C 语言源程序中添加一些编译预处理命令,可以使程序更加简洁、易读,还可以提高程序的运行效率。预处理发生在编译之前。C 语言中提供了三种编译预处理功能,即宏定义、文件包含和条件编译。为了和一般语句区分,预处理命令以# 开头,且结尾不加分号,并通常占用一个独立的行。 1宏定义宏定义是指用一个指定的标志符来代替程序中的一个片段。宏定义可以分为无参数的宏和有参数的宏两种。无参数的宏的一般形式如下:#define 宏名 表达式其中表达式可以是常数、字符或字符串、表达

74、式和语句,甚至可以为多条语句。宏名为一个合法的标志符。例如:#define PI 3.1415926在程序中,宏定义用标志PI 代表数字3.1415926,这样程序中凡是用到这个数据量时,都用PI 来表示,编译预处理时将所有的PI 替换为3.1415926。这样使程序更加简洁,避免数据不一致问题。同时如果要修改PI 的值,如改变其有效数据的个数时,不需要在所有用到PI 的地方做修改,只要修改宏定义即可。67宏定义时也可以使用已经定义的宏。【案例4-23】 计算圆的面积。#include#define PI 3.14#define R 5#define AREA PI*R*Rvoid main(

75、) printf(r=%dnarea=%.2fn,R,AREA);程序运行结果如下:r=5area=78.50带参数的宏的一般形式如下:#difine 宏名(形参列表)表达式例如:#define MUL(x,y) x*y在程序编译预处理阶段,ADD(i,j )被替换为ij。其中的i和j 作为实参替换了宏定义中的形参x和y。使用带参数的宏定义时,宏定义中的表达式中的形参通常用括号括起来,以避免会出错。例如程序中有如下语句:m=MUL(i+1,j-1);68则在编译时可将其替换为:m=i+1*j-1;这显然是不对的,因此应该将宏定义为:#define MUL(x,y) (x)*(y)可以将程序中反

76、复使用的运算表达式或简单函数定义为带参数的宏,这样可以使程序更简洁。【案例4-24】 带参数的宏。#include#define MAX(x,y) xy?x:y;void main() int a10; int max; int i; printf(请输入10个正整数:n); for(i=0;i10;i+) scanf(%d,&ai); max=a0; for(i=0;i10;i+) max=MAX(max,ai); printf(最大值为:%dn,max);69程序运行结果如下:请输入10个正整数:7 2 9 5 1 4 10 3 8 6最大值为:10带宏的参数和函数非常类似,但是两者之前还

77、是有本质的区别的:(1)宏替换在编译预处理时进行,不占运行时间,只占编译预处理的时间,函数调用在程序运行时进行,占运行时间。(2)带参数的宏只是简单的字符替换,并不计算带参数的表达式的值,而函数需要计算实参表达式的值,并赋值给形参。(3)宏名没有类型,宏参数也没有类型的问题,宏中使用的参数的类型是在参数定义的时候确定的,所以宏中的表达式中参数可以是任意类型;而函数中则不同,函数中对数据类型有严格的定义。70 2文件包含文件包含是指一个程序中将另一个指定的文件的全部内容都包含进来,文件包含的一般形式为:#include 文件名 或#include 使用文件包含命令时,相当于将include 后面

78、的源文件的全部内容写在语句include 后面的位置。713条件编译在一般情况下,源程序中所有的语句都参与编译,但是有时候只希望对其中某一部分在满足一定条件时才进行编译,即对部分内容指定编译条件,也就是条件编译。条件编译的形式有以下几种。形式一的定义如下:#ifdef 标志符 程序段1#else 程序段2#endif功能为:如果标志符已经被#define命令定义过,则在程序编译时只处理程序段1,否则只处理程序段2。形式二的定义如下:#ifndef 标志符 程序段1#else 程序段2#endif功能为:如果标志符没有被#define命令定义过,则在程序编译时只处理程序段1,否则只处理程序段2。

79、72形式三的定义如下:#if 常量表达式 程序段1#else 程序段2#endif功能为:如果常量表达式的值为真,则处理程序段1,否则处理程序段2。【案例4-25】 条件编译1。#include #define CHOICE1#ifdef CHOICE1 #define PI 3.1415926#else #define PI 3.14#endifvoid main() float r,area; scanf(%f,&r); area=r*r*PI; printf(area=%fn,area);程序运行结果如下:5area=78.53981573【案例4-26】 条件编译2。#include

80、#define LOW 1void main() char ch; ch=getchar(); #if LOW if(ch=A&ch=a&ch=z) ch=ch-32; /小写变大写 #endif printf(%cn,ch);程序运行结果如下:AacC744.3.4 任务实现1问题描述在前面的章节中,已经逐步实现了学生信息管理系统中的一部分功能,现在可以使用函数来完成每一部分的实现。所以能完成的功能有:(1)显示功能菜单。(2)添加学生信息。(3)查找学生信息。(4)计算学生平均成绩。(5)计算各科成绩最高分。(6)显示所有学生成绩信息。2要点解析可以将每一个功能在一个函数中实现。即将程序分

81、为多个模块,每个模块实现一个功能。现在需要将这些功能用函数的形式组织起753程序实现#include#include#include/以下为自定义函数说明语句void welcome(); /显示欢迎信息void menu(); /显示功能菜单void choose(); /选择功能函数void insert(); /插入学生成绩信息void search(); /查找学生成绩信息void total(); /课程信息统计void del(); /删除学生信息void print(); /显示学生成绩信息int max(int s); /计算成绩最大值int min(int s); /计算成绩

82、最小值int average(int s); /计算成绩平均值int no100=201201,201202,201203,201204,201205;/学生学号,初始化设置5个学生的信息char name10020=Jack,Rose,Lily,Tom,Ming; /最大存储100个学生的姓名int score1003=69,73,82,71,90,76,93,96,89,70,67,82,84,88,81; /每个学生有三门课,分别为C、Java和Datebaseint num=5; /数组中有效数据长度int realnum=5; /学生数目int on=1; /标志是否结束程序运行76

83、void main()/*主函数*/ welcome(); menu(); while(1) choose(); if(on=0) printf(系统运行结束!n); break; /显示欢迎信息void welcome() printf(n|-|n); printf(| 欢迎使用学生信息管理系统 |n); printf(|-|n);/显示菜单栏void menu() printf(|-STUDENT-|n); printf(|t 1. 添加学生信息 |n); printf(|t 2. 查找学生信息 |n); printf(|t 3. 删除学生信息 |n); printf(|t 4. 课程成绩

84、统计 |n); printf(|t 5. 显示所有学生信息 |n); printf(|t 6. 显示功能菜单 |n); printf(|t 0. 退出系统 |n); printf(|-|nn);/选择要执行的功能77void choose() int c; printf(选择您要执行的功能,0-6:); scanf(%d,&c); switch(c) case 0:on=0; return; break; case 1: insert(); break; case 2: search(); break; case 3: del(); break; case 4: total(); break;

85、 case 5: print(); break; case 6: menu(); break; /添加学生信息78void insert() printf(请输入学生学号,格式为2012*:); int x; scanf(%d,&x); if(x201299) printf(输入信息不合法!n); return; for(int i=0;inum;i+) if(noi!=0&noi=x) printf(该学号已经存在!n); return; nonum=x; printf(输入学生姓名:); scanf(%s,&namenum); printf(请输入C语言成绩:); scanf(%d,&sc

86、orenum0); printf(请输入Java成绩:); scanf(%d,&scorenum1); printf(请输入数据库成绩:); scanf(%d,&scorenum2); num+; realnum+; printf(添加成功!n);/查找学生信息79void search() int x; printf(请输入要查询的学生学号:); scanf(%d,&x); if(x201299) printf(您查询的学生不存在!n); return; for(int i=0;inum;i+) if(noi=x) break; if(noi!=x) printf(您查询的学生不存在!n);

87、 return; else printf(学号tt姓名ttC语言tJavat数据库n); printf(%dtt,noi); printf(%stt,namei); for(int j=0;j3;j+) printf(%dt,scoreij); printf(n); /删除学生信息80void del() int x; printf(请输入要删除的学生学号:); scanf(%d,&x); if(x201299) printf(您输入的学生信息不存在!n); return; for(int i=0;inum;i+) if(noi=x) break; if(noi!=x) printf(您输入的

88、学生信息不存在!n); return; else nox=0; realnum-; printf(删除成功!n); /统计课程信息81void total() int i,j;int n=0; int score2 3100; for(i=0;inum;i+) if(noi=0) continue; else for(j=0;j3;j+) score2jn=scoreij; n+; printf(统计tC语言tJavat数据库n); printf(最高分t%dt%dt%dn,max(score20),max(score21),max(score22); printf(最低分t%dt%dt%dn

89、,min(score20),min(score21),min(score22); printf(平均分t%dt%dt%dn,average(score20),average(score21),average(score22);/显示学生信息82void print() printf(共有%d名学生,学生信息如下:n,realnum); int i,j; printf(学号tt姓名ttC语言tJavat数据库n); for(i=0;inum;i+) if(noi=0) continue; printf(%dtt,noi); printf(%stt,namei); for(j=0;j3;j+) p

90、rintf(%dt,scoreij); printf(n); return;int max(int s) int maxs; int i; maxs=s0; for(i=0;inum;i+) if(noi=0) continue; else if(maxssi) maxs=si; return maxs;83int min(int s) int mins; int i; mins=s0; for(i=0;isi) mins=si; return mins;int average(int s) int sum=0; int i; for(i=0;inum;i+) if(noi=0) contin

91、ue; else sum=sum+si; return sum/realnum;84程序运行结果如下:|-| 欢迎使用学生信息管理系统 |-|-STUDENT-| 1. 添加学生信息 | 2. 查找学生信息 | 3. 删除学生信息 | 4. 课程成绩统计 | 5. 显示所有学生信息 | 6. 显示功能菜单 | 0. 退出系统 |-|选择您要执行的功能,0-6:5共有5名学生,学生信息如下:学号 姓名 C语言 Java 数据库201201 Jack 69 73 82201202 Rose 71 90 76201203 Lily 93 96 89201204 Tom 70 67 82201205

92、Ming 84 88 81选择您要执行的功能,0-6:485统计 C语言 Java 数据库最高分 93 96 89最低分 69 67 76平均分 77 82 82选择您要执行的功能,0-6:1请输入学生学号,格式为2012*:2012100输入信息不合法!选择您要执行的功能,0-6:1请输入学生学号,格式为2012*:201204该学号已经存在!选择您要执行的功能,0-6:1请输入学生学号,格式为2012*:201208输入学生姓名:Lucy请输入C语言成绩:89请输入Java成绩:75请输入数据库成绩:91添加成功!选择您要执行的功能,0-6:5共有6名学生,学生信息如下:86学号 姓名 C

93、语言 Java 数据库201201 Jack 69 73 82201202 Rose 71 90 76201203 Lily 93 96 89201204 Tom 70 67 82201205 Ming 84 88 81201208 Lucy 89 75 91选择您要执行的功能,0-6:2请输入要查询的学生学号:201208学号 姓名 C语言 Java 数据库201208 Lucy 89 75 91选择您要执行的功能,0-6:2请输入要查询的学生学号:201207您查询的学生不存在!选择您要执行的功能,0-6:3请输入要删除的学生学号:201207您输入的学生信息不存在!选择您要执行的功能,0

94、-6:387请输入要删除的学生学号:201203删除成功!选择您要执行的功能,0-6:2请输入要查询的学生学号:201203您查询的学生不存在!选择您要执行的功能,0-6:6|-STUDENT-| 1. 添加学生信息 | 2. 查找学生信息 | 3. 删除学生信息 | 4. 课程成绩统计 | 5. 显示所有学生信息 | 6. 显示功能菜单 | 0. 退出系统 |-|选择您要执行的功能,0-6:5共有5名学生,学生信息如下:学号 姓名 C语言 Java 数据库201201 Jack 69 73 82201202 Rose 71 90 76201204 Tom 70 67 82201205 Min

95、g 84 88 81201208 Lucy 89 75 91选择您要执行的功能,0-6:4统计 C语言 Java 数据库最高分 89 90 91最低分 69 73 76平均分 76 78 82选择您要执行的功能,0-6:0程序运行结束!88课后练习1以下函数值的类型是 。fun(float x) float y; y=3*x-4; return y;Aint B不确定 Cvoid Dfloat2有如下函数调用语句:fun(rec1,rec2+rec3,(rec4,rec5);该函数调用语句中,含有的实参个数是 。A3 B4 C5 D有语法错3有以下函数定义:void fun(int n,dou

96、ble x) 若以下选项中的变量都已经正确定义且赋值,则对函数fun的正确调用语句是 。Afun(int y,double m); Bk=fun(10,12.5); Cfun(x,n); Dvoid fun(n,x);894有以下程序:int f(int n) if(n= =1) return 1; else return f(n-1)+1;main() int i,j=0; for(i=1;i3;i+) j+=f(i); printf(%dn,j);程序运行后的输出结果是 。A4 B3 C2 D15在C语言中,一个函数一般由两个部分组成,它们是 。6以下程序运行后,输出结果是 。int d=

97、1;fun (int p) int d=5; d+=p+; printf(%d,d);main() int a=3; fun(a); d+=a+; printf(%dn,d);907以下程序的输出结果是 。int f() static int i=0; int s=1; s+=i; i+; return s;main() int i,a=0; for(i=0;i5;i+) a+=f(); printf(%dn,a);8以下程序的输出结果是 。t(int x,int y,int cp,int dp) cp=x*x+y*y; dp=x*x-y*y; main() int a=4,b=3,c=5,d

98、=6; t(a,b,c,d); printf(%d %d n,c,d); 919运行下列程序后的w值为 。main() int w=2,k; for (k=0,k3,k+) w = f(w); printf(%dn,w); Int f(int x) int y=0;Static int z=3; y+;z+;return(x+y+z);10已有变量定义和函数调用语句:int a=10,b=-17,c; c=fun(a,b); fun函数的作用是计算两个数之差的绝对值,并将差值返回调用函数,请编写fun函数。11已有变量定义和函数调用语句:int x=87;isprime(x);函数isprime用来判断一个整型数a是否为素数,若是素数,函数返回1,否则返回0。请编写isprime函数。9212一函数,输入一行字符(只包含空格和字母),将此字符串中最长的单词输出。13一函数,输入一个十六进制数,输出相应的十进制数。14给出年、月、日,计算该日是该年的第几天。15定义一个函数digit(n,k),它回送整数n的从右边开始数第k个数字的值。例如:digit(15327,4)=5digit(289,5)=093

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 建筑/环境 > 施工组织

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号