寒假作业3

合作者:周政演 031602543 博客链接魏璐炜 031602136 博客链接

相同部分


大致设计思路

根据讨论 制定了两种思路:

  1. 将数字与运算符建立映射,利用随机数函数在运算符位置上模拟出四种运算符,舍弃除数为0的情况以及输出不为整数的情况。
  2. 将各种情况讨论出来,再一一编码。

编码规范


因为想到自己制订的编码规范未必规范,所以上网查找了一些编码规范,经过筛选,共同学习后制订出了编码规范

一、排版: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;
}

主函数中的循环语句中有多个条件语句,用与剔除各种不符合要求的题目输出。

完整代码

测试结果

不足之处

文件的运行速度过慢,有时要等待数秒才能输出题目,我们认为原因如下:

  1. 剔除不符合要求的输出的条件语句太多,导致重复的运行过多。
  2. 随机数的产生是以时间为种子,短时间内系统输出时间是不变的,所以会产生相同的随机数,这样这些相同的随机数都会被剔除,直到一个时刻产生符合要求的随机数为止。

分工与合作

github的提交链接

https://github.com/Vancasola/cooperation

差异部分

合作过程以及体会

  • 接到题目后,两个人很快组成一个小组,对题目进行讨论。开始时先讨论清楚题意,然后分享各自的思路,二人综合之后,决定采用如下思路:将数字与运算符建立映射,利用随机数函数在运算符位置上模拟出四种运算符,舍弃除数为0的情况以及输出不为整数的情况。031602543先打出主函数的结构,经过讨论后定下模块,查找资料学习随机数的原理以及使用。由031602543编写获取题数、求两数四则运算函数值、获取符号的函数,由031602136编写随机数函数。因为这次作业并不是很难,所以二人只在git上提交了几次就把程序写完了,若是在更大的项目上合作,恐怕需要花费的时间和精力就多得多了,提交和更改的次数也会增加许多。两个人在编码的时候,都是使用多组测试数据,将代码尽量检查到没有错误,才push上去,这样减少了对方的工作量。
  • 在学习git时遇到了许多问题,其中,在push代码到仓库时,总是显示没有权限,网络上普遍的说法时缺少ssh key,需要将sshkey添加到github中的setting里,尝试多次后,发现并不奏效,后来向助教学长请教了一下,发现是并未将成员添加到仓库里面,这是教程里面没有提到的,将成员添加后,就顺利地解决了这个问题。

分工

  • 031602543 主要负责编码、调试程序、解决git中遇到的问题、完成随笔。
  • 031602136 主要负责界面美化、翻译、记录过程。
  • 分工github地址

031602543附:

程序二的尝试(只尝试核心思路)

分数的尝试

原文地址:https://www.cnblogs.com/Cleveland/p/6414158.html