“人向猿进阶”之软件工程第二课
今晚是我第三次因为学习而晚睡,第一次是高考第一天晚上,白天发挥失常未能入睡,第二次是去年全国数学建模大赛加急时间写论文,而第三次就是今晚。从上学期的编译方法课开始,我就发现自己的编程能力越来越不好,逐日下降,完全称得上是三天不练手生,十天不练脑生,当时本想通过大创来增强自己的动手能力,但由于各种意外事件的发生,把想法越推越没,直到现在。这周我们的软件工程课的作业是设置自己的学习进度条和给上周的随机加减法程序增加功能,本来是周三布置的作业,结果到今晚才差强人意的完成,中途有些时间是因为上考研课没了的,还有十几个小时是因为个人情感波动太大而浪费的,剩下没多少的时间不是被这儿折腾完,就是被那儿浪费,尽管自己的计划是满满的,但是却给变化留了太多的机会。特别是在这次的情感波动中,几近让自己崩溃,无奈,都已经打算好了放弃考研之路,并且现在自己感觉自己已经不像之前那样喜欢这门专业,喜欢编程,认为自己不是很适合做这门行业,相对来说我更喜欢模电数电之类的电类学科和硬件设施,从小我就比较喜欢电路,爱动手去做一些东西,经常被我妈说成闲人,所以更加让我深陷,都已经打算好放弃之前的一些努力,成为一个普普通通的过得去大学生就好。幸好我是幸运的,丟之桑榆,收之东隅,拥有很多关心自己的朋友、同学以及陌生人,是他们让我鼓起了勇气,重新点燃了自己的奋斗之火、追求之光。非常感谢我的人生中有他们的身影存在。
这次的作业是:扩充 《四则运算》题目的功能,要求:题目避免重复;可以定制数量和打印方式;可以控制下列参数;是否有乘除法;是否有括号;数值范围加减有无负数;除法有无余数;是否支持分数(真分数、假分数…);是否支持小数(精确到多少位?);打印中每行的间隔;
从我第一次拿到这个题目时,我觉得这个题目不难,可能就是思维不全有漏洞,毕竟给是给小学生做的算术题,故不能太难,所以我打一开始就是奔着实现全部功能去得,所以考虑了链表存储,数组存储,结构体存储等,总想找到一个简单的简便的方法去实现这些功能,因为毕竟这些功能代码逐一实现起来不难,况且以前比这复杂都写过,这个不算什么。经过那么久的思考,我开始上机验证自己的代码准确性,从一开始到现在的代码量我肯定写了超过500行的代码了,但现在留下来的300不到,其他的都被pass了,想法总是美好的,代码运行总是残酷的,并且现在的程序是自己不满意的,功能的实现比较初略浅显,各部分代码如下:
1:首先是主函数部分,设置了数值范围和题量的参数,把加减乘除各类运算分开列在各子函数里面。这是现在的设计,之前的想法是,让各个子函数只实现生成对应的加减乘除算式,而主函数实现对应的用户答题结果的判断,由于除法和减法的复杂性,编写到一半的时候就舍弃了,所以就留下了现在的半成品。
int main () { int a=1; while(a) { int y=0,z=0; y=show(); printf("\t请输入练习多少题\n"); scanf("%d",&z); printf("\t请输入数值范围\n"); scanf("%d",&SS); switch(y) { case 1:addition(z);break;//进入加法 case 2:sub(z);break;//进入减法 case 3:mul(z);break;//进入乘法 case 4:division(z);break;//进入除法 case 5:un(z);break;//进入混合运算 } printf("\t是否继续做练习(0-否,1-是)"); scanf("%d",&a); } return 0; }
2:用户互动操作提示,设计了用户的选择,但总体思路很过一般,基本上是属于“大路”货的类型。本来自己原先的想法是设计加、减、乘、除、加减乘除、括号运算、多个数的四则运算等功能,写到四分之一的时候,发现生成这些类的算式容易,但是如果想告诉用户做题是否准确以及正确答案,这部分的功能实现比较复杂,特别是对于多个数的混合运算,需要用到上学期学到的算符优先关系来处理判断,计算出结果,如果涉及到分数与小数又会是下一个难题。但由于时间的有限,以及之前的浪费,使得不得不放弃一些选择,实现了基本的计算。
int show()//输入指令 { printf("\t小学生四则运算\n"); printf("\t1:独立加法练习\n"); printf("\t2:独立减法练习\n"); printf("\t3:独立乘法练习\n"); printf("\t4:独立除法练习\n"); printf("\t5:加减乘除混合练习\n"); printf("\t请选择你所需的服务练习\n"); int yy; scanf("%d",&yy); while((yy<1)||(yy>5)) { printf("输入错误,请重新输入\n"); scanf("%d",&yy); } return yy; }
这部分的运行展示:
3:这部分介绍的是加法,可以说是四则运算中最简单、最容易实现的一个功能。只需要根据随机种子产生随机数,然后再把每次产生的两个存在数组里面,后面产生的数与前面产生的数进行比较,如果两个数都相同,则重新生成,避免用户做到重复的题目,然后计算结果,与输入结果比较,若正确输出正确,错误,输出错误与正确结果。
void addition(int z)//随机生成加法e1+e2 { int zz=0; zz=z; while(z--) { int C[100][2];//存储输出的题目 int e1,e2; int ans; srand((int)time(0));//随机种子 e1=rand()%SS;//随机数 C[z][0]=e1; e2=rand()%SS; C[z][1]=e2; int m=0,mm=0; for(m=zz;m>z;m--) { if((C[z][0]==C[m][0])&&(C[z][1]==C[m][1])) { z=z+1; mm=1; break; } }//对将要输出的题目做题目重复判断 if(mm==1) continue; printf("%d+%d=",e1,e2); scanf("%d",&ans);//结果输入 if(ans==(e1+e2)) printf("right\n"); else printf("error right=%d\n",e1+e2); } }
4:接下来是减法,减法相对于加法来说,多出了输出是否存在负数,由于是小学生,所以在程序当中,把每次产生的减数与被减数进行比较,如果减数大于被减数,则把两个数互换,保证没有负数的情况出现,同样的对产生的数进行查询,保证没有重复的题目出现,并且对输入的结果进行验证。
void sub(int z)//随机生成减法e1-e2 { int zz=0; zz=z; while(z--) { int C[100][2];//存储输出的题目 int e1,e2; int ans; srand((int)time(0));//随机种子 e1=rand()%SS;//随机数 C[z][0]=e1; e2=rand()%SS; C[z][1]=e2; int m=0,mm=0; for(m=zz;m>z;m--) { if((C[z][0]==C[m][0])&&(C[z][1]==C[m][1])) { z=z+1; mm=1; break; } }//对将要输出的题目做题目重复判断 if(mm==1) continue; if(e1<e2)//对调小数和大数,保证结果无负数 { ans=e1; e1=e2; e2=ans; } printf("%d-%d=",e1,e2); scanf("%d",&ans);//题目作答 if(ans==(e1-e2)) printf("right\n"); else printf("error right=%d\n",e1-e2); } }
5:这是乘法,与加法等同。
void mul(int z)//随机生成乘法e1*e2 { int zz=0; zz=z; while(z--) { int C[100][2];//存储输出的题目 int e1,e2; int ans; srand((int)time(0));//随机种子 e1=rand()%SS;//随机数 C[z][0]=e1; e2=rand()%SS; C[z][1]=e2; int m=0,mm=0; for(m=zz;m>z;m--) { if((C[z][0]==C[m][0])&&(C[z][1]==C[m][1])) { z=z+1; mm=1; break; } }//对将要输出的题目做题目重复判断 if(mm==1) continue; printf("%d*%d=",e1,e2); scanf("%d",&ans);//题目作答 if(ans==(e1*e2)) printf("right\n"); else printf("error right=%d\n",e1*e2); } }
6:然后是除法,除法是在减法的基础上,多了分母为0,分子分母同时为0,分数的时候是小数表示还是真分数表示等。对于分母为0分子不为0的情况,只需要简单的把分子分母互换,然后查看是否已有该题目,再输出;对于分子分母同时为0的情况,就重新生成算式;对于出现不整除的情况,采取的是小数表示,用两位小数表示计算结果。暂时还不支持分数与分数的运算。剩下的都与另外三种运算类似。
void division(int z)//随机生成除法e1/e2 { int zz=0; zz=z; printf("\t若为小数,请保留4位小数\n"); while(z--) { int C[100][2];//存储输出的题目 int e1,e2; srand((int)time(0));//随机种子 e1=rand()%SS;//随机数 C[z][0]=e1; e2=rand()%SS; C[z][1]=e2; int m=0,mm=0; for(m=zz;m>z;m--) { if((C[z][0]==C[m][0])&&(C[z][1]==C[m][1])) { z=z+1; mm=1; break; } }//对将要输出的题目做题目重复判断 if(mm==1) continue; int ee; if(e2==0)//当分母为0时,分子分母调换 { ee=e1; e1=e2; e2=ee; } if((e1==0)&&(e2==0))//若分子分母都为0,重新生成题目 { z=z+1; continue; } printf("%d/%d=",e1,e2); float ans; scanf("%f",&ans);//题目作答 float e3; e3=e1*1.0/e2;//对输出结果进行处理,保证输出4位小数 if(ans==e3) printf("right\n"); else printf("error right=%.2f\n",e3); } }
7:这是加上括号的运算,随机的产生加减乘除四种运算符,生成(e1 op1 e2) op2 e3的式子,当然这很局限性,并且程序结构的设计也不好,对于两次调用switch我是很反对的,但是如果不这样的话,我就想用子函数来替换,然后就想把整个程序都联系起来用这种方法,但最终没有选择这条路,也许是跟心情有关吧(毕竟自己是个很感性的人,一点小事都能让自己浪费半天),有点着急了,毕竟身边的人已经做好了,如果自己在去重新编码,会用更多的时间,毕竟现在的编码能力已经没有以前的水平了,只能写写简单的,复杂的都不想再去动脑去实践了,先就这样吧。
void un(int z)//加减乘除综合题 { while(z--)//(e1 op1 e2) op2 e4 { int op1; float ans; srand((int)time(0)); int e1,e2; printf("(");//( e1=rand()%SS;//随机数 e2=rand()%SS; if(e1<e2)//对调小数和大数,保证结果无负数 { ans=e1; e1=e2; e2=ans; } printf("%d",e1);//e1 op1=rand()%4; float e3; switch(op1) { case 0:printf("+");e3=e1+e2;break; case 1:printf("-");e3=e1-e2;break; case 2:printf("*");e3=e1*e2;break; case 3:printf("/");e3=e1*1.0/e2;break; }//op1 printf("%d)",e2);//e2) int e4; e4=rand()%SS; op1=rand()%4; float e5; switch(op1) { case 0:printf("+");e5=e3+e4;break; case 1:printf("-"); if(e3<e4) { ans=e3; e3=e4; e4=ans; } e5=e3-e4;break; case 2:printf("*");e5=e3*e4;break; case 3:printf("/"); while(e4==0) e4=rand()%SS; e5=e3*1.0/e4;break; }//op2 printf("%d=",e4);//e4= scanf("%f",&ans); if(ans==e5) printf("right\n"); else printf("error right=%.2f\n",e5); } }
8:这是之前自己设计的一些未曾用上的十分之一成品,尽管大多数十分之一的成品已经被删除或者修改,但是既然这点留下来了,就当做一种记忆的怀恋吧。
/*void bracket(int e1,int e2)//随机生成括号(e1 op e2) { printf("("); int op1; op1=rand()%4; switch(op1) { case 1:addition(e1,e2); case 2:sub(e1,e2); case 3:mul(e1,e2); case 4:division(e1,e2); } printf(")"); }*/ /*void natural(int a)//随机生成自然数e { int s1=0; memset(A,0,sizeof(A)); while(a--) { srand((int)time(0)); A[s1]=rand()%100; s1++; } }*/
对于自己的程序,我持很不乐观的态度,因为有些可以单独作为子函数存在的循环代码,没有被提出来,想要一个判断答题是否正确的功能,就丧失了一部分其他的东西。本来可以简化程序的地方,也没有简化,程序看起来很繁琐很复杂,放在这里时时提醒自己吧。
说完了自己的东西,下面开始其他的吧。在自己编写这个程序的时候遇到了烦心事,然后就把有每位同学博客链接的文章找到,看了很多的其他同学的博客,有自己班的,有一起上课那班的,还有另外2个班的,心中五味杂全。以前的自己总以为我的大学没有白费,至少我会那么些其他人(周围的同学)不会的,有几个其他人没有的证书,有还算不错的成绩,有,,,但今晚我发现自己以前妄浪了,是,以前的自己和其他人比是优越的,但现在还是吗?时间在变化,人也再变化,而别人一直在不断行走,而我却原地踏步。就拿今晚看到的某个同学的博客,原来自己和他的差距现在已经达到了这种地步,亏自己一直还以应该和他水平差不多而随便,尽管有时候自己看见他再努力,但都不以为然,然而今天打响了我的耳光。又拿自己看到的另外几个同学的博客来说,大一大二的时候,我扪心自问,心里面真的是没有把他们当做过对手,从他们那里感到过压力,但当看到他们博客上规规整整的C++、java时,我很鄙视自己,我们都是同样学的,为什么现在别人用C++,java用的这么好,而自己却是当时用的好,现在却是门外汉,连最基本的语法语义都不记得了,现在的自己恐怕是别人都未曾看在眼里了吧。很多时候有机会可以让自己改变的,但是自己却放弃了,别人却坚持了下来,所以现在的落后是必然的,好好反思反思现在的自己,好好总结总结曾经的一切,真真切切的规划规划明天,那样才可能在剩下的短暂时间里重新获得主动权与俯视权,我愿在前方披荆斩棘,乘风破浪,丢弃该丢弃的,拿起早已放下的,哪怕有一天被带回原点,但我相信不会有这一天。