C语言博客作业03--函数

0.展示PTA总分


1.本章学习总结

1.1 学习内容总结

函数的定义
- 函数包括库函数自定义函数 。例如,scanf(),printf()函数是由C语言系统直接定义的,再编辑时可以直接调用使用,属于库函数;而有时我们需要使用一些有特定功能的函数,而这些函数是C语言系统中没有的,因此我们需要自己定义,这些自己定义的函数就属于自定义函数。C语言的函数在程序中必然是属于某一种数据类型,我们称之为函数类型。

函数定义的一般形式

函数类型 函数名(形参)   //函数的首部
{
函数实现过程   //函数的主体(函数实现功能的主体,又若干语句组成,完成我们需要的特定功能,一般是使用return返回函数值)
}

函数的调用
- 在完成上述的函数定义后,我们可以开始在写代码中调用函数。如果调用的是库函数,需要在程序开始时的include后加上相对应的头文件;如果调用的是自定义函数,需要定义好与所调用函数相对应的定义函数

函数调用的一般形式

函数名(实参);//实参可以是常量,变量,与表达式
1. 需要的注意的是,任何程序都是从主函数main开始进行,当遇到调用函数时,暂时跳出主函数,前往执行该调用函数,当该调用函数执行结束后,在返回主函数,从刚刚跳出的地方(即暂停的位置)继续执行主函数。
2. **函数的返回值**:现在函数中计算对应表达式的值,当进行到return时,结束函数,同时将表达式的值返回主函数。且,return的值可以是0,1·····这样的常量,那么此时返回主函数的值就是常量。(**注意**:函数的返回值只能有一个!!)

一般形式

return 表达式(或者是常量)

函数的声明
- 在C语言中,要求函数先定义再调用,因此,如果是使用自定义函数,就需要在函数调用前,加上函数声明(位置一般写在头文件的下一行)。函数的声明主要是说明函数的类型,以及参数的类型与数量,从而保证程序在编译进行时能判断对该函数的调用是否正确。需要注意的是:函数声明以分号结尾,而函数的调用时后面不能跟分号。

函数声明的一般形式

函数类型 函数名(参数);

局部变量和全局变量

1.局部变量
- 迄今为止,在程序中使用的变量都定义在函数内部,它们的有效使用范围被局限于所在的函数内。因此主调函数只有通过参数传递,才能把实参数据传递给函数使;同样,形参的改变也不会影响到实参变量。这种变量的有效使用范围,最大程度保了各函数之间的独立性,避免函数之间相互干扰。
- C语言中把定义在函数内部的变量称为局部变量,局部变量的有效作用范围局限于所在的函数内部。形参是局部变量。
- 使用局部变量可以避免各个函数之间的变量相互干扰,当使用了同名的形参,且与相互函数实参变量同名时,由于分属不同函数,它们有各自不同的变量实体和使用范围,不会相互千扰。C语言的这个特性在结构化程序设计中非常有用。
- 除了作用于函数的局部变量外,C语言还允许定义作用于复合语句中的局部变量,其有效使用范围被局限于复合语句内,一般用作小范围内的临时变量。(以上关于局部变量的内容来自《C语言程序设计》P107-108)

2.全局变量
- 局部变量虽然保证了函数的独立性,但程序设计有时还要考虑不同函数之间的数据交流,及各函数的某些统一设置。当一些变量需要被多个函数共同使用时,参数传递虽然是一个办法,但必须通过函数调用才能实现,并且函数只能返回一个结果,这会使程序设计受到很大的限制。为了解决多个函数间的变量共用,C语言允许定义全局变量。
- 定义在函数外而不属于任何函数的变量称为全局变量。全局变量的作用范围是从定义开始到程序所在文件的结束,它对作用范围内所有的函数都起作用。
- 全局变量的定义格式与局部变量完全一致,只是定义位置不在函数内,它可以定义在程序的头部,也可以定义在两个函数的中间或程序尾部,只要在函数外部即可。
- 一般情况下把全局变量定义在程序的最前面,即第一个函数的前面。
- 由于全局变量和局部变量的作用范围不同,允许它们同名。当某函数的局部变量与全局变量同名时,在该函数中全局变量不起作用,而由局部变量起作用。对于其他不存在同名变量的函数,全局变量仍然有效。同样,当函数局部变量与复合语句的局部变量同名时,以复合语句为准。
- 全局变量可以帮助解决函数多结果返回的问题,但全局变量更多地用于多函数间的全局数据表示。(以上关于全局变量的内容来自《C语言程序设计》P108-109)

3,总结
- 在我们看来,全局变量比使用局部变量自由度大,更方便。一旦定义,所有函数都可直接使用,连函数参数都可省略,甚至函数返回结果个数也不受限制,不需要使用return语句,可以直接通过全局变量回送结果。从表面上看,全局变量确实能实现这些要求,但对于规模较大的程序,过多使用全局变量会带来副作用,导致各函数间相互干扰。如果整个程序是由多人合作开发的,各人都按自己的想法使用全局变量,相互的干扰可能更严重。如果我们把变量比喻成抗菌药的话,显然不管病情轻重,一律吃最高档的抗菌药,效果虽好,但带来的副作用是不言而喻的,对症下药才是最科学的。因此在变量使用中,应尽量使用局部变量,从某个角度看使用似乎受到了限制;但从另一个角度看,它避免了不同函数间的相互干扰,提高了程序质量。
- 全局变量虽然可以用于多个函数之间的数据交流,但一般情况下,应尽量使用局部变量和函数参数。(以上内容来自《C语言程序设计》P112)

静态局部变量
- 在静态存储区中,除了全局变量外,还有一种特殊的局部变量一一静态局部变量。它存放在静态存储区,不会像普通局部变量那样因为函数调用结束而被系统回收,它的生存周期会持续到程序结束。由于存储单元被保留,一旦含有静态局部变量的函数被再次调用,则静态局部变量会被重新激活,上一次函数调用后的值仍然保存卷,可供本次调用继续使用。
静态变量定义格式:

static 类型名 变量表
- 静态变量赋初值只在函数第一次调用时起作用,若没有赋初值,系统将自动赋值0。
- 静态变量与全局变量均位于静态存储区,它们的共同点是生存周期贯穿整个程序执行过程。区别在于作用范围不同,全局变量可作用于所有函数,静态变量只能用于所定义函数,而不能用于其他函数。静态变量和全局变量一样,属于变量的特殊用法,若没有静态保存的要求,不建议使用静态变量。C语言除了静态局部变量外,C语言也宥静态全局变量,它的作用与程序文件结构有关。(以上关于静态变量的内容来自《C语言程序设计》P113-115)

1.2 本章学习体会及代码量

1.2.1 学习体会
在这两周中,代码量有所增加,但由于运动会以及大作业的原因,在后一周的代码量会比前一周少许多。这两周的大量活动,导致我的空余时间大幅减少,对PTA题目的的练习一直处于比较迟钝的状态,所有的时间几乎都用在了不断地赶作业和写新作业上。我感觉自己已经有一段时间没有把时间拿出来好好地研究和研究代码了,同时,课程进度已经到了二维数组,我已经开始感觉在学习新知识上已经有些勉强了。自我反省后,我发现最近这两周自己的状态已经开始下滑了,PTA题集的练习也没有及时赶上。我甚至一度开始怀疑自己是否还对打代码怀有热情,但是当我开始写大作业时,在凌晨2点终于将这几天断断续续的思路理清楚并实现我的基础设想时,我还是可以感受到内心的激动。所以,虽然课程已经开始逐渐加深难度,学习新知识也开始逐渐吃力,但是这并不能成为我打消自己热情的理由。遇到难题,坚持下去,多学,多练,多问,总能攻克难关。运动会结束了,接下来这段时间,我会把精力转移到学习上面来,明确接下来的目标,保持对代码的热情,继续努力!

1.2.2 代码累计


2.综合作业

题目:小学生口算表达式自动生成系统

功能要求:
1.完成1-3年口算题自动出题系统
2.注意每个年级运算数要求,运算数和运算符要随机生成
3.用户每选择一个难度级别后必须输入题目数量,能统计用户的正确率。用户每算一题,若错误,给出正确答案。 用户中途退出,不继续做题,需要有个提示操作可中途退出。

注意:
软件界面必须友好,多加文字提示,能让用户自己当前做什么,接下来怎么做,每步操作可以退到主菜单界面。
-注意异常数据处理,如除0错误、不合法数据、临界数据,系统保证运行时候不崩溃。
注意函数封装,不管是几位数的加减乘除运算,相同功能的代码应该都封装都一函数,通过参数传递实现代码覆盖。也可以考虑数据输入、输出等函数封装,尽量不要把代码都放main中。各种异常情况也可以单独封装函数处理,让程序的扩展性更强。
扩展功能:
可以设置答题时间,用户超过答题时间,提示不能继续做题,重新选抽题。请查阅C的时间函数。
扩展难度级别,比如出现2步加减乘除,然后乘除优先计算。比如2+3*4运算

3.函数功能及全局变量介绍


3.1.全局变量

3.2.List()函数

功能:输出选择菜单,并对用户提示使用该系统的方法。
思路:通过菜单选择进入下一个函数
截图:

3.3.main()函数

功能:实现程序的开始与结束。
思路:用于写入随机数种子。引导用户进入下一个内容。
截图:

3.4.Judge()函数

功能:指引用户选择等级并输入,同时判断输入的是否合法。
思路:通过Judge()函数来让用户进行选择进入的年级。
截图:

3.5.GradeChoose()函数

功能:识别上一个函数传进来的正确的等级,并进行判断进入的下一个函数
思路:利用一个简单的函数来进行识别。
截图:

3.6.GradeOne()函数

功能:计算关于一年级的口算
思路:使用独立一个函数封装

3.7.GradeTwo()函数

功能思路与一年级差不多

3.8.GradeThree()函数

4.运行结果截图,测试用例。


运行界面:

一年级

1.10以内三个数连加

2.整十数加一位数的加法

3.整十数减整十数的减法

4.两位数减整十数的减法

5.100以内连加连减混合运算

二年级

1.1-9以内的表内乘除法

2.整十数加整十数的加法(进位的)

3.尾数是0三位数加法(和在一千以内的)

(这个数据实在是太难测出来了...)
4.整百数加减法(和超过一千的,退位的)

5.10以内除法加法混合运算

三年级

1.三位数加三位数的加法(含连续进位的):

2.一位数乘一位、二位、三位数



3.万以内的加减法

5. 调试碰到问题及解决办法

1.随机数的取法:
- 因为口算题都是随机生成的,因此取随机数的范围很重要。比如在乘法表时,用rand()%10是可能会产生0,后来改成random()%9+1就不会了。
- 在Judge()函数时想使用递归但是都会输出两次,后来经过多次调试,将op = scanf("%c", &grade);放在do循环中,成功实现。

6.大作业总结

  • 这次作业一开始做的比较艰难,思路不清晰,脑子里也没有明显的框架,所以一开始写的烦躁,进度也很缓慢。在最后这几天快要截止了,听从了一些同学的建议,从头开始画程序框图,把自己想要实现的内容一条条整理排序,最后整理出来了一些比较清晰的思路。
  • 在开始的时候,我是先尝试写出一年级的一道计算题,然后慢慢将一年级的一些内容慢慢拓展开来,最后先将一年级代码用函数封装,再由同样的方法做出二,三年级的。
  • 可能是整理时间与练习的不够,代码整体还是存在不少的缺陷,每个年级也并没有包含老师提供的所有情况,在整体的美观上做的也不太好,尤其是拓展方面也不太好,整体的拓展功能的思路还是比较模糊,算是遗憾吧。但是我想我可以通过后面的学习和练习来一步步的改进和优化它。
posted on 2019-11-03 22:34  蔡浩伟  阅读(365)  评论(1编辑  收藏  举报