合作者:周政演 031602543 博客链接魏璐炜 031602136 博客链接
相同部分
大致设计思路
根据讨论 制定了两种思路:
- 将数字与运算符建立映射,利用随机数函数在运算符位置上模拟出四种运算符,舍弃除数为0的情况以及输出不为整数的情况。
- 将各种情况讨论出来,再一一编码。
编码规范
因为想到自己制订的编码规范未必规范,所以上网查找了一些编码规范,经过筛选,共同学习后制订出了编码规范。
一、排版:1、关键词和操作符之间加适当的空格。
2.相对独立的程序块与块之间加空行
3.较长的语句、表达式等要分成多行书写。
4.划分出的新行要进行适应的缩进,使排版整齐,语句可读。
5.长表达式要在低优先级操作符处划分新行,操作符放在新行之首。
二、注释
1.注释要简单明了。
2.边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。
3.在必要的地方注释,注释量要适中。注释的内容要清楚、明了,含义准确,防止
注释二义性。保持注释与其描述的代码相邻,即注释的就近原则。
4.对代码的注释应放在其上方相邻位置,不可放在下面。
5.变量、常量的注释应放在其上方相邻位置或右方。
三、命名
1.较短的单词可通过去掉“元音”形成缩写;
2.较长的单词可取单词的头几发符的优先级,并用括号明确表达式的操作顺序,避
免使用默认优先级。
四、可读性
1.避免使用不易理解的数字,用有意义的标识来替代。
2.不要使用难懂的技巧性很高的语句。
3.源程序中关系较为紧密的代码应尽可能相邻。
五、变量
1.去掉没必要的公共变量。
2.构造仅有一个模块或函数可以修改、创建,而其余有关模块或函数只访问的公共
变量,防止多个不同模块或函数都可以修改、创建同一公共变量的现象。
3.仔细定义并明确公共变量的含义、作用、取值范围及公共变量间的关系。
4.明确公共变量与操作此公共变量的函数或过程的关系,如访问、修改及创建等。
六、函数、过程
1.一个函数最好仅完成一件功能。
2.为简单功能编写函数。
3.函数的功能应该是可以预测的,也就是只要输入数据相同就应产生同样的输出。
4.尽量不要编写依赖于其他函数内部实现的函数。
5.检查函数所有参数输入的有效性。
八、程序效率
1.编程时要经常注意代码的效率。
2.在保证软件系统的正确性、稳定性、可读性及可测性的前提下,提高代码效率。
3.不能一味地追求代码效率,而对软件的正确性、稳定性、可读性及可测性造成影
响。
4.编程时,要随时留心代码效率;优化代码时,要考虑周全。
5.在多重循环中,应将最忙的循环放在最内层。
程序一的实现与结果测试
函数头
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<stdbool.h>
int get_integer(void);//获取题目数
void get_number(int *pa,int *pb,int *pc);//获取数字
char get_sign(void);//获取运算符号
int value(int,int,char); //求两个数四则运算的值
bool language=true;
在程序中有五个自定义函数,建立这么多的自定义函数的目的是简化main函数,将函数分成许多小的功能,各个函数的功能在代码中均有注释。
双语界面
这次程序的操作是
获取题目数
int get_integer(void)
{
int n,num;
char ch;
bool judge=true;
if(language) printf("请输入0~10的整数题数:\n");
else printf("Please enter 0~10 integer question.");
n=scanf("%d",&num);
if(num>10||num<1)//限定为0~10的题目数
judge=false;
while(n!=1||judge==false)//给用户再次尝试的机会
{
if(language) printf("请输入一个0~10整数,如2,3.\n");
else printf("Please enter 0~10 interger,such as 2,3.\n");
while((ch=getchar())!='\n')
continue;
n=scanf("%d",&num);
if(num>10||num<1)
judge=false;
else
judge=true;
}
return num;
}
该段代码的作用是获取题目数,其中代码排除了0~10以外的题数以及非整数的输入。循环语句中运用了最近学习的一个小技巧:若是获取是如ndsjfbs这样的一段输入,循环语句会给用户一次提示并给予他们重新输入的机会,同时将用户的错误输入清空。
提供重新输入的机会
获取随机数
void get_number(int *pa,int *pb,int *pc)//获取随机的数字
{
srand(time(NULL));
*pa=rand()%11;
*pb=rand()%11;
*pc=rand()%11;
}
其中srand()rand()来自头文件stdlib.h,time()来自头文件time.h。srand()用来初始化rand(),而srand()中的time(NULL)是用时间作为参数,使种子不断变化,从而产生不同的“随机数”。
rand()函数返回一个整数值,此时将这个整数值用11取余,就可以得到范围是0~10的数。
获取符号
char get_sign(void)//将运算符对应于数字,用随机数模拟随机运算符
{
char sign;
int int_sign;
srand(time(NULL));
int_sign=rand()%4+1;
switch(int_sign)
{
case 1:sign='+';break;
case 2:sign='-';break;
case 3:sign='*';break;
case 4:sign='/';break;
}
return sign;
}
在该自定义函数中,建立了一个数字到运算符号的映射,1、2、3、4对应着字符+、-、*、/。产生一次随机数便能返回一个运算符,模拟随机产生运算符的功能。
计算二元表达式的值
int value(int a,int b,char sign)//计算两个数的四则运算
{
int v;
switch(sign)//注意除数不能为0,整数输出
{
case '+':v=a+b;break;
case '-':v=a-b;break;
case '*':v=a*b;break;
case '/':v=a/b;break;
}
return v;
}
本次作业只输出3个数字的题目,若是一一讨论,将大大增加程序的复杂程度,于是化整为零,编写出两个数的运算函数,这样增加了程序的可读性和可移植性,若是要增加到4个数字、5个数字的混合运算,只需在main函数中稍作更改即可。
主函数
int main(void)
{
int i,num,count=0;//num为题数,count用于计算题数
int a,b,c,answer;//abc为计算的数字,answer是用户输入的答案
int * pa,* pb,* pc;
pa=&a;pb=&b;pc=&c;//用于获取数字的函数
char sign1,sign2;
char ch;
printf("选择中文版请输入1。\nEnter 0 to choose English.");
scanf("%d",&language);
num=get_integer();
if(language)
printf("请输入一个整数答案(输入e结束并得出结果)\n");
else printf("Please enter an integer answer(e to quit and get the result).\n");
for(i=1;i<=num;)//自增符号放于文件尾,防止用continue剔除不合要求题目时减少了循环次数
{
sign1=get_sign();
sign2=get_sign();
get_number(pa,pb,pc);
if(sign2=='/')//剔除除数为0和答案不为整数的题目
if(c==0||(float)(b/c)==(b/c))continue;
if(sign1=='/')//剔除除数为0和答案不为整数的题目
if(value(b,c,sign1)==0||(float)(b/c)==(b/c))continue;
printf(" %d %c ( %d %c %d)=",a,sign1,b,sign2,c);
if(scanf("%d",&answer)!=1)break;//获取用户的答案,输入e时退出
b=value(b,c,sign2);
if(answer==value(a,b,sign1))
{
if(language)
printf("答案正确!\n");
else printf("You're right!\n");
count++;
}
else {
if(language)printf("答案错误!答案为%d\n",value(a,b,sign1));
else printf("It's wrong,the right answer is %d\n",value(a,b,sign1));
}
i++;
}
if(language)printf("正确题数:%d",count);
else printf("You have %d right answer.",count);
return 0;
}
主函数中的循环语句中有多个条件语句,用与剔除各种不符合要求的题目输出。
完整代码
测试结果
不足之处
文件的运行速度过慢,有时要等待数秒才能输出题目,我们认为原因如下:
- 剔除不符合要求的输出的条件语句太多,导致重复的运行过多。
- 随机数的产生是以时间为种子,短时间内系统输出时间是不变的,所以会产生相同的随机数,这样这些相同的随机数都会被剔除,直到一个时刻产生符合要求的随机数为止。
分工与合作
github的提交链接
https://github.com/Vancasola/cooperation
差异部分
合作过程以及体会
- 接到题目后,两个人很快组成一个小组,对题目进行讨论。开始时先讨论清楚题意,然后分享各自的思路,二人综合之后,决定采用如下思路:将数字与运算符建立映射,利用随机数函数在运算符位置上模拟出四种运算符,舍弃除数为0的情况以及输出不为整数的情况。031602543先打出主函数的结构,经过讨论后定下模块,查找资料学习随机数的原理以及使用。由031602543编写获取题数、求两数四则运算函数值、获取符号的函数,由031602136编写随机数函数。因为这次作业并不是很难,所以二人只在git上提交了几次就把程序写完了,若是在更大的项目上合作,恐怕需要花费的时间和精力就多得多了,提交和更改的次数也会增加许多。两个人在编码的时候,都是使用多组测试数据,将代码尽量检查到没有错误,才push上去,这样减少了对方的工作量。
- 在学习git时遇到了许多问题,其中,在push代码到仓库时,总是显示没有权限,网络上普遍的说法时缺少ssh key,需要将sshkey添加到github中的setting里,尝试多次后,发现并不奏效,后来向助教学长请教了一下,发现是并未将成员添加到仓库里面,这是教程里面没有提到的,将成员添加后,就顺利地解决了这个问题。
分工
- 031602543 主要负责编码、调试程序、解决git中遇到的问题、完成随笔。
- 031602136 主要负责界面美化、翻译、记录过程。
- 分工github地址