C博客作业03--函数
0.展示PTA总分
1.本章学习总结
1.1 学习内容总结
- 函数可以将一个较大的任务分解成若干个小的任务。而且设计得当的函数可以把具体操作细节对外界隐藏起来,从而使整个程序结构清楚。
- 一个程序中的函数是互相独立的,可以互相调用。函数调用时需要注意实参和形参必须一一对应(包括数目和类型)。
- 函数设计的基本原则是:函数规模小、函数功能单一、函数接口定义要清楚。
- 在函数这一章我新学到一个静态变量 static int,这种变量具有记忆功能即当第N次使用这个变量时它的值是第N-1次完成运算的值。并且如果该变量没有赋初值的话,系统会自动给静态变量赋上0的初值。这一作用在后一章节的数组中起着重要的作用。
- 函数不能嵌套定义,也就是说一个函数不能从属于另一个函数。函数之间可以相互调用,但是任何函数不能调用main函数,main函数是被操作系统调用的。
- 在调用函数过程中发生的实参与形参间的数据传递是“值传递”,只能由实参向形参传递数据,是单向传递,不能由形参传给实参。
- 全局变量,其作用域从定义变量的位置开始到本源文件结束,全局变量的优点就是它的缺点,每个函数都可以对该变量进行赋值,一不小心也容易出错。
下面列举的是我从中学到了不同思维方式以及解题思路的三道编程题
打印空心菱形或打印数字金字塔.(这一类题目最重要的是找到每一行输出的数字与行数以及每一行的个数的关系)
1. 使用一个中间数mid令它等于输出菱形的中间那一行。
2.灵活使用一个绝对值函数令每一行输出的字符或者是数字满足题目要求。
伪代码如下:
定义整型变量hight用于输入菱形的高度;
定义字符型变量ch用于输入第一个输出的字符;
定义字符型变量bh用于输出后面不同的字符;
定义整型变量mid用于储存菱形的中间行;mid=(hight+1) / 2
for int i=1 to hight do i++
for int j=1 to mid do j++ //输出每一行第一个数字前面的空格
输出空格
end for
for int k=1 to hight - 2 * abs(mid - i) do k++ //输出每一行所对应的字符与空格
if (k == 1 || k == hight - 2 * abs(mid - i))//每一行循环到的位置为第一个数字或者为最后一个数字
bh = ch + mid - 1 - abs(mid - i)//每一行输出的字符与列数的中间数以及每一行的位置有关
输出bh
else
输出空格
end if
end for
end for
输出指定范围内的Fibonacci数.(Fibonacci数列从第三项开始为前面两个数字之和)
定义两个函数,一个函数【 int fib( int n ) 】的作用是返回第N个Fibonacci数字,另一个函数【 void PrintFN( int m, int n ) 】输出从m到n中所含Fibonacci数。
伪代码如下:
定义整型变量sum=1(sum的初始化是有诀窍的,如果输入的n为小于2的值,还是输出sum)用于储存前两个数的和;
定义整型变量FirstNumber=1用来循环前面的数字;
定义整型变量SecondNumber=1用来循环后面的数字;
定义整型变量temp用于储存还没有被赋值的SecondNumber;
for int i=3 to n do i++ //循环得到第n个Fibonacci数
sum = firstnumber + secondnumber;
temp = secondnumber;
secondnumber = sum;
firstnumber = temp;
end for
返回sum的值
定义整型变量flag=0用来判断是否为输出的第一个数,如果是第一个数则输出数字,如果不是输出空格加数字
定义整型变量count=0用来判断是否有Fibonacci数
for int j=1 to fib(j) > n do j++
if (fib(j) >= m)
if (flag == 0)
输出大于m的Fibonacci数
flag = 1//输出第一个Fibonacci数后重新赋值,让后面的数输出时前面加上空格
count = 1//有Fibonacci数字输入,给count赋值为1
else
输出空格+Fibonacci数
end if
end if
end for
if(count==0)//在m到n的数字没有进入前面的循环体
输出"No Fibonacci number"
end if
验证哥德巴赫猜想.(任何一个不小于六的偶数可以拆解能两个素数的和,让前面输出的素数为最小的满足条件的素数)
定义两个函数,一个函数【 int prime( int p ) 】判断是否为素数,另一个函数【 void Goldbach( int n ) 】输出一个偶数为两个素数之和且第一个素数为最小数
伪代码如下:
定义整型变量flag=1用来判断是否为素数,flag=1,为素数;flag=0,不是素数
if(P==1)
flag=0;//1不是素数
end if
if(P==2)
flag=1;//2是素数
end if
for int i= 2 to i*i<=P do i++
if (p % i == 0)
flag = 0;//能被整除说明不是素数
end if
end for
if (flag==1)
return 1;//素数,该函数返回1
else
return 0;//不是素数,该函数返回0
end if
定义整型变量number1用来储存素数的值
定义整型变量number2用来储存素数的值
for number1=2 to number1=n do number1++ //number1是从2开始往上加的,就可以满足题目要求输出的number1为最小素数
number2=n-number1;
if(prime(number1)&&prime(number2)) //调用第一个函数判断number1和number2是否为素数
输出n=number1+number2
break;//输出满足条件的唯一表达式后结束循环
end if
end for
1.2 本章学习体会及代码量学习体会
1.2.1 学习体会
- 函数的内容,其实就是把代码模块化、板块化。不再是让代码挤在一起,阅读起来很累;如果没有加注释,既不容易观察也不易改错纠正。函数的命名也是一大特色之一,一个清楚可观的命名可以让读者很容易知道函数的内容,例如int isprime(int number)可以很直观的知道这个函数是在判断number是否为素数。老师也在上课的时候讲过,函数的命名最好使用动词+名词,代码的可读性增强了许多。函数有较强的独立性,而且可以相互调用。函数是完成一个个特定任务的语句集合,它能完成你所想要的某种特定任务,当你要用时,只需要调用它即可,在后续的修改或是维护过程中,只需要针对这一个进行修改即可。函数的使用可以减少重复代码的使用,节省了时间也节省了空间;后续如果代码出了错误,只需要更改某一个函数的内容即可不用大幅度的修改代码。
- 在函数的使用方面,我的能力还是比较薄弱的。当刷函数的PTA时,我还没有达到那种一看完题目脑海中就浮现整个题目的大体框架的能力。我每次做题目都要在纸上罗列一遍过程再在编译器VS上面打代码,我做题的速度与我们班的大神比起来简直就是惨不忍睹。有时候,一些晦涩难懂的题目,我甚至连题目的意思都读不懂,这时我对自己就会产生自我怀疑,我是不是就是比别人差?而且后面的题目,我越来越感觉到力不从心,但是我从来没选择放弃,既然我凭着一腔孤勇选择了网络工程这个专业,那么我就会在这条路上奋战下去。只要肯下功夫,会有进步的。无论如何,我对代码、编程都保留着最初的那份热情。遇到困难是要去克服而不是埋怨。我上周六去参加ACM的模拟赛,对我来说,那些题目无疑是难的,但是每当自己成功拿下一道题目,那种无与伦比的喜悦只有自己才会懂。我会一直追逐这类喜悦,永不停歇。
1.2.2 代码累计
2.综合作业:小学生口算表达式自动生成系统
1.本次作业的函数关系图
2.函数功能及全局变量介绍
2.1.全局变量
- choice //判断年级
- levle //判断难易程度
- right //统计题目正确的个数
- count //输入的做题目的总数量
2.2.ListMenu()函数
菜单函数,输出本程序所包含的三个年级以及不同年级所做的题目的难易程度
2.3AdditionAndSubtraction()函数
加法或者减法函数,定义一个随机数t=rand()% 2,如果t0,生成+,进行加法运算;如果t1,生成-,进行减法运算。
2.4MultiplicationAndDivision()函数
乘法或者除法函数,定义一个随机数t=rand()% 2,如果t0,生成*,进行乘法运算;如果t1,生成 / ,进行除法运算。
2.5ContinuousAdditionandSubtraction()函数
三个数字的加减混合运算,定义一个随机数t=rand()% 2,如果t0,生成+,进行加法运算;如果t1,生成-,进行减法运算。让前面两个数进行运算后,将运算结果储存到sum,重复随机数t的操作,进行sum与第三个数字的运算,结果仍旧储存到sum里面。这样sum 就是整个表达式最后的结果。
2.6FourArithmeticOperations()函数
四则运算函数,前面的运算符号生成 + 或 - ,后面的运算符号生成 * 或 / ,先完成后面的乘除运算,并把运算结果赋值给sum,在令sum完成与前面第一个数字的加减运算,运算后并把最后的结果赋值给sum。这样sum 就是整个表达式最后的结果。
2.7Exit()函数
中途退出函数:小学生没做完一道题目,系统就提示他,是否继续做题,若他选择否,系统确定他是否真的退出,确定退出后即结束本次答题。否则将继续作答。
2.8randomnumber()函数
产生随机数函数,不同年级产生不同的随机数范围,同一年级不同难度也会产生不同的随机数范围。
3.运行结果截图,测试用例。
一年级:
二年级:
三年级:
答完所有题目之后,有一个正确率的计算:
4. 调试碰到问题及解决办法
- 中途退出的函数使用不当,整个系统使用了两个Exit函数,调试界面出现了两次重复的提示退出语句。
解决方法:将Exit();这一语句删除。
-
统计做对题目的变量right在main函数中无法读入。
解决办法:因为在每个运算函数后面都返回了那个right的值,所以把之前的right数给顶掉了。只需把每个函数后的返回那一行代码删除即可。
-
使用生成随机数函数时,题目无法显示
解决方法:随机数生成函数 ,只能返回一个值,但是我之前让它返回了三个值,根据不同年级的需求,让随机数满足需求生成,并返回。
-
定义double类型变量rate,但是它的值还是非0即1
解决办法:造printf("%d",right) 检查right的值是否正确,right的值是正确的,灵光一闪,想到right,count均为整型变量,即使rate是实数型变量,但是系统没有接收到这一指令,于是在rate的表达式前添加1.0 *。
-
四则运算的符号无法显示
解决办法:输出的随机数是double类型的,但是我使用的是%d,全部更改过来即可。
5.大作业总结
- 当我看到这次的博客作业的时候,我傻眼了。构建一个程序让小学生做口算???我当时脑子里毫无头绪,根本找不到着眼点去写这个程序。我也到网上百度了一下别人写的口算系统,五花八门,眼花缭乱。之后便是看见别人的代码,有了一点思路,就开始写,这里写一点,那里写一点,整个代码四分五裂,没有一点框架可言。写完第一遍的时候,程序是崩溃的,无法运行,代码量五六百行,无从下手改错,又有很多是重复的,改起来都很困难。总结第一次的教训,开始写第二遍,这次也只是比第一次好那么一点点,程序可以运行,但是答案相差甚大。之后又是一番费尽心力的修改、查错。没有办法让程序达到我想要的口算效果。无可奈何之下,再来了一遍,是的,没错,500多行的代码重写了两遍,写最后一遍的时候,我没有拿到电脑就去敲代码,而是在纸上将这个大题目一点一点的拆分,拆分成八个函数(如上所诉的八个函数),先写函数,在完成main函数中的内容。这样算是比较清晰整个代码的流程。写完之后这个作业大概就出了雏形。运行该代码,再一点点的找错,修改。这一遍虽然也出现好几点错误,但是可以从错误里面分析出是哪个函数出了问题,慢慢的就完善了这个代码。
- 这次作业我学到了一个很重要的概念——框架,在我们拿到一道题目的时候,我们不能急着就去写代码,因为某一瞬间的灵光不足以写完整个代码,最后还是需要一点一点的去完善,在完善的过程中,就会发现有很东西考虑的不完善甚至是两个相反的东西,还有可能是整个代码要重写。我以后如果要写一个大型代码时,我会先在纸上罗列题目要求实现的功能,用函数去封装每一个不同的功能,完成各个功能的函数之后,再去写主函数;在main函数中调用功能不同的函数,最后根据运行结果的差异慢慢去修改这个程序。