结对编程第二次作业

一.题目要求

这次作业我们选择的是题目一

本次作业要求两个人合作完成,驾驶员和导航员角色自定,鼓励大家在工作期间角色随时互换,这里会布置两个题目,请各组成员根据自己的爱好任选一题。
题目1:
我们在刚开始上课的时候介绍过一个小学四则运算自动生成程序的例子,请实现它,要求:
能够自动生成四则运算练习题
可以定制题目数量
用户可以选择运算符
用户设置最大数(如十以内、百以内等)
用户选择是否有括号、是否有小数
用户选择输出方式(如输出到文件、打印机等)
最好能提供图形用户界面(根据自己能力选做,以完成上述功能为主)

二.任务分配

  • 我的角色:驾驶员
    能够完成全部代码工作,程序基本实现全部要求功能,并将代码上传至coding.net或者GitHub代码托管系统中
    能够对导航员在本次编程工作中起到的作用给出客观评价,并完成500字以上的总结
  • 领航员:陈卓~领航员博客地址
    能够辅助驾驶员完成全部代码工作,并且为关键函数选用合适的覆盖标准设计测试用例,并编写代码进行单元自动测试
    能够根据上次作业的代码检查表对驾驶员的本次工作进行评价
    能够对本次工作完成500字以上的总结

三.需求分析

   小学四则运算自动生成程序,解决的主要问题是小学老师或者学生家长给小学生出题的问题,老师和家长给学生出题时,需要很多的时间和精力。使用这个程序可以节省很多时间,并且可以自主选择题目模式,出题也可以实现多样化。

四.代码实现

完整代码已提交至Github~代码地址

  • 代码可以实现的功能有,作业中要求的六种功能(自动生成题目,定义题目数量,定义最大数字,选择是否有小数,选择是否有括号,选择是否输出为文件格式)。以及一些附加功能:给出正确答案,当减法不够减,除数为零以及无法整除的解决方法等;

下面为代码主要功能的解释:

1.函数原型以及定义

int count;///定义题目数量
int max;///定义最大数字
int ffloat;///选择是否有小数
int file;///选择是否输出为文件
int bracket;///选择是否有括号
int getChoice();
void Menu();
int integer(int);
int decimal(int);
FILE *fp;///定义文件

2.用户选择功能函数

  • 这个函数功能是让用户输入功能菜单中的选项对应的数字,来选择自己想要使用的功能.
int getChoice()
{
	int choice;
	scanf("%d", &choice);
	return choice;
}

3.功能菜单

  • 这个函数的功能是显示可供选择的几种出题方式,方便用户选择,对应上面的用户选择功能.
void Menu()
{
	printf("===================================
");
	printf("
欢迎使用小学生四则运算练习软件
");
	printf("
选项如下:
");
	printf("	1、加法练习  (有括号时为加法和除法的复合运算)
");
	printf("	2、减法练习  (有括号时为减法和乘法的复合运算)
");
	printf("	3、乘法练习  (有括号时为加法和乘法的复合运算)
");
	printf("	4、除法练习  (有括号时为减法和除法的复合运算)
");
	printf("
===================================
");
}

4.整数的运算

①产生随机整数

  • 随机数生成功能我是第一次使用,下面附上解释.

rand函数是计算机C语言中的函数,是真正的随机数生成器,而srand()会设置供rand()使用的随机数种子。如果在第一次调用rand()之前没有调用srand(),那么系统会自动调用srand()。而使用同种子相同的数调用 rand()会导致相同的随机数序列被生成。
--引用自搜狗百科

srand(time(NULL)); ///初始化随机数种子
	for (j = 1;j <= 2 * count; j++)
	{
		num1[j] = rand() % max + 1;           ///取0—max之间的随机数
		num2[j] = rand() % max + 1;
		num5[j] = rand() % max + 1;
	}

②选择运算符号以及运算式中是否存在括号(这里只举出加法的例子,其他符号与加法类似)

  • 当运算式中没有括号时,直接输出加法运算式,当运算式中有括号时,输出加法和除法的复合运算式.
switch (n)
	{
	case 1:
		operation = '+';
		if (bracket == 1)
		{
			for (i = 1;i <= count;i++)
			{
				printf("(%d %c %d)/ %d = 
", num1[i], operation, num2[i], num5[i]);
				fprintf(fp, "(%d %c %d)/ %d = 
", num1[i], operation, num2[i], num5[i]);
			}
		}
		break;

③运算式中没有括号时的输出方式(fprintf为文件格式输出,实现方法在后面会有解释)

if (bracket == 0)
		{
			printf("%d%c%d= 
", num1[i], operation, num2[i]);
			fprintf(fp, "%d%c%d= 
", num1[i], operation, num2[i]);
		}

④给出正确答案(同样是以加法为例,其他符号类似)

printf("正确答案为: 
");
	fprintf(fp, "正确答案为: 
");
	for (i = 1;i <= count;i++)
	{
		switch (operation)
		{
		case '+':
			if (bracket == 1)  ///有括号时正确答案的计算
				ranswer1[i] = (num1[i] + num2[i]) / num5[i];
			else if (bracket == 0) ///无括号时正确答案的计算
				ranswer1[i] = num1[i] + num2[i];
			break;

下面附上整数运算部分的完整代码~

int integer(int n)
{
	int i, j, m;
	int ranswer1[count];
	int t = 0;                ///临时变量
	char operation;            ///运算符号
	int num1[count];               ///操作数1
	int num2[count];
	int num5[count];               ///操作数2
	srand(time(NULL)); ///初始化随机数种子
	for (j = 1;j <= 2 * count; j++)
	{
		num1[j] = rand() % max + 1;           ///取0—max之间的随机数
		num2[j] = rand() % max + 1;
		num5[j] = rand() % max + 1;
	}

	switch (n)
	{
	case 1:
		operation = '+';
		if (bracket == 1)
		{
			for (i = 1;i <= count;i++)
			{
				printf("(%d %c %d)/ %d = 
", num1[i], operation, num2[i], num5[i]);
				fprintf(fp, "(%d %c %d)/ %d = 
", num1[i], operation, num2[i], num5[i]);
			}
		}
		break;

	case 2:
		operation = '-';
		if (bracket == 1)
		{
			for (i = 1;i <= count;i++)
			{
				printf("(%d %c %d)* %d = 
", num1[i], operation, num2[i], num5[i]);
				fprintf(fp, "(%d %c %d)* %d = 
", num1[i], operation, num2[i], num5[i]);
			}
		}
		break;

	case 3:
		operation = '*';
		if (bracket == 1)
		{
			for (i = 1;i <= count;i++)
			{
				printf("(%d + %d)%c %d = 
", num1[i], num2[i], operation, num5[i]);
				fprintf(fp, "(%d + %d)%c %d = 
", num1[i], num2[i], operation, num5[i]);
			}
		}
		break;

	case 4:
		operation = '/';
		if (bracket == 1)
		{
			for (i = 1;i <= count;i++)
			{
				printf("(%d - %d)%c %d = 
", num1[i], num2[i], operation, num5[i]);
				fprintf(fp, "(%d - %d)%c %d = 
", num1[i], num2[i], operation, num5[i]);
			}
		}
		break;
	}

	///减法操作不够减的时候,交换两个操作数
	for (i = 1;i <= count;i++)
	{
		if ((operation == '-') && (num1[i]<num2[i]))
		{
			t = num1[i];
			num1[i] = num2[i];
			num2[i] = t;
		}

		///除法操作中的除数,即num2为0时就将num2强制置为1
		///将num1的值赋值给num1*num2,防止不能整除
		if (operation == '/')
		{
			if (num2[i] == 0)
			{
				num2[i] = 1;
			}
			num1[i] = num1[i] * num2[i];        ///防止num1不能被num2整除的语句
		}
		if (bracket == 0)
		{
			printf("%d%c%d= 
", num1[i], operation, num2[i]);
			fprintf(fp, "%d%c%d= 
", num1[i], operation, num2[i]);
		}
	}
	///计算并给出正确答案
	printf("正确答案为: 
");
	fprintf(fp, "正确答案为: 
");
	for (i = 1;i <= count;i++)
	{
		switch (operation)
		{
		case '+':
			if (bracket == 1)  ///有括号时正确答案的计算
				ranswer1[i] = (num1[i] + num2[i]) / num5[i];
			else if (bracket == 0) ///无括号时正确答案的计算
				ranswer1[i] = num1[i] + num2[i];
			break;

		case '-':
			if (bracket == 1)
				ranswer1[i] = (num1[i] - num2[i])*num5[i];
			else if (bracket == 0)
				ranswer1[i] = num1[i] + num2[i];
			break;

		case '*':
			if (bracket == 1)
				ranswer1[i] = (num1[i] + num2[i])*num5[i];
			else if (bracket == 0)
				ranswer1[i] = num1[i] + num2[i];
			break;

		case '/':
			if (bracket == 1)
				ranswer1[i] = (num1[i] - num2[i]) / num5[i];
			else if (bracket == 0)
				ranswer1[i] = num1[i] + num2[i];
			break;
		}
		printf("%d  
", ranswer1[i]);
		fprintf(fp, "%d  
", ranswer1[i]);
	}
	printf("继续请按1,结束请按0
");///选择是否结束程序
	scanf("%d", &m);
	if (m == 1)
		return 1;
	else
		return 0;
}

5.小数运算

  • 小数运算基本上与整数运算相同,下面仅将有区别的地方单独放出来.

产生随机小数

srand(time(NULL));     ///初始化随机数种子
	for (j = 1;j <2 * count;j++)
	{
		num3[j] = rand() / (double)(RAND_MAX / max) + 1;///产生随机小数
		num4[j] = rand() / (double)(RAND_MAX / max) + 1;
		num6[j] = rand() / (double)(RAND_MAX / max) + 1;
	}

6.输出为文件格式

①定义一个指向文件的指针变量fp

FILE *fp;

②如果选择输出为文件,则打开文件,使用文件方式为只写

if (file == 1)
   fp = fopen("四则运算.txt", "w");

③输出为文件格式(读写对象为文件)

fprintf(fp, "%.2f  
", ranswer2[i]);

④文件使用完毕,关闭数据文件

fclose(fp);
  • 另外,在添加文件功能时,出现了一个问题,只能生成一个空文件,而文件里没有任何内容,后来发现第一次运算结束,结果输出到文件后,程序会自动进行下一次运算,这时生成的空文件会把之前文件中存入的内容覆盖掉,文件中自然什么都没有。解决方法是将功能菜单中的部分内容转移到了主函数里,并调整了一下功能选择顺序,并且添加了一个用户自主选择是否继续执行程序的功能,问题就解决了。.

7.用户自主选择是否退出程序

printf("继续请按1,结束请按0
");///选择是否结束程序
	scanf("%d", &m);
	if (m == 1)
		return 1;
	else
		return 0;

8.主函数

int main(void)
{
	int a = 1, choice;        ///接收用户的选择
	do      ///循环开始功能
	{
		Menu();                  ///显示菜单
		printf("请输入需要打印题目数量:
");
		scanf("%d", &count);
		printf("请输入题目中的最大数字:
");
		scanf("%d", &max);
		printf("请选择是否需要小数(是为1,否为0):
");
		scanf("%d", &ffloat);
		printf("请选择是否输出到文件(是为1,否为0):
");
		scanf("%d", &file);
		printf("请选择是否需要括号(是为1,否为0):
");
		scanf("%d", &bracket);
		printf("请输入你的选择(0--4):
");
		if (file == 1)
			fp = fopen("四则运算.txt", "w");
		choice = getChoice();
		if (choice != 0)
		{
			///控制choice的范围
			if (choice<0 || choice>5)
				choice = 1;
			if (ffloat == 0)
			{
				a = integer(choice);
			}
			if (ffloat == 1)
			{
				a = decimal(choice);
			}
		}
		if (choice == 0)
		{
			a = 0;
			if (file == 1)
				fclose(fp);
			break;                ///用户选择0,退出循环(退出系统)
		}
	} while (a == 1);
	printf("感谢使用本软件
");
	return 0;
}

9.减法操作时不够减,除数为零,无法整除的解决方法

①加法操作不够减时,交换减数和被减数的位置

if ((operation == '-') && (num1[i]<num2[i]))
		{
			t = num1[i];
			num1[i] = num2[i];
			num2[i] = t;
		}

②除数为零时,将除数强行置1

if (num2[i] == 0)
			{
				num2[i] = 1;
			}

④不能整除时,将乘数与被乘数的乘积赋值给被乘数。(仅限于整数运算)

  • 但是这个功能有一个bug,当将乘数与被乘数的乘积赋值给被乘数后,被乘数的值可能会超出用户给定的最大数。.
num1[i] = num1[i] * num2[i];

五.领航员评价

本次编程过程中,领航员为陈卓,他为我的工作做出了很大的帮助,因为我的编程工作几乎都是在寝室完成的,所以与领航员的但部分交流也是在网上进行的。这次编程过程中,我编写了不止一个版本的程序,每次实现完一部分功能,便将这一部分的代码发送给陈卓一份,陈卓同学会将这一部分代码中出现的问题以及可以进行改正升级的部分指出来,使编程的效率和正确率提高了很多,并且他会提出代码中可以添加的附加功能,使代码更加完善,严谨。
因为我的编程水平并不高,所以编程速度比较慢,导致这次结对编程的进度跟着变慢,留给领航员进行单元测试以及代码复审的时间有些紧张,也非常感谢领航员对我的理解以及鼓励。
结对编程是我第一次接触,以前自己一个人敲代码时,很多问题会忽略,导致程序漏洞百出,最后一点一点的修补,非常麻烦。结对编程很好地解决了这一问题,两个人同时进行编程,不仅效率提高很多,也提高了代码的正确率和功能的完整性。
最后附上工作照一张~

六.个人总结

  • 在这次程序编写过程中,也是遇到了很多问题。首先,我的编程水平并不高,我选择担任驾驶员这个角色时,很担心自己能不能完成这个工作,还好算是基本上把功能都完成了,虽然有些功能实现的并不完美。我所编写的代码中的很多功能实现都比较繁琐,代码整体语言比较简单,对于领航员来说也许是比较易于理解,因为没有使用什么高级的算法和语句。在编程过程中整体方向走偏了一次,这个代码整体功能是四则运算的出题程序,而我第一次实现的是一个四则运算的在线做题程序,只有当用户输入一道题的答案时,下一道题才会出现。后来又仔细阅读题目后发现和题目的要求并不统一,经过修改之后完成了题目的整体要求,当然这也影响了我们这次作业的进度。对于文件输出问题,因为以前从来都没有接触过以文件格式输出的要求,所以也没有做过这方面的练习,所以学习这一方面的知识也占用了一部分时间。在这次结队编程过程中,不断地发现问题,解决问题,也学习了很多新的知识。所以说,每一次作业的完成都不是一帆风顺的,每一次任务都是一次发现问题并且提升自我的机会。
  • 另外,我习惯使用的编程环境是Codeblocks,在做这次作业时,Codeblocks出现了一些问题,也许是某一次下载软件或者卸载软件或者配置环境变量时,把Codeblocks的编译器给整丢了,无法进行编译,所有程序都无法运行,将其卸载并在电脑的软件管理里重新下载安装后,问题仍然没有解决。最后的解决方法是,进入Codeblocks官网重新下载了一个带编译器的Codeblocks(codeblocks-17.12mingw-setup.exe)。在我电脑的软件管理里下载的Codeblocks是没有自带编译器的。进入官网之后,点击Downloads,然后点击下图中的Download the binary release

Windows系统选择codeblocks-17.12mingw-setup.exe进行安装即可,这个是带编译器的文件

关于此问题的更多内容可以查看这篇文章

原文地址:https://www.cnblogs.com/ncc123/p/8836073.html