一 题目及要求

实现一个小学四则运算自动生成程序的例子,要求:

  • 能够自动生成四则运算练习题
  • 可以定制题目数量
  • 用户可以选择运算符
  • 用户设置最大数(如十以内、百以内等)
  • 用户选择是否有括号、是否有小数
  • 用户选择输出方式(如输出到文件、打印机等)
  • 最好能提供图形用户界面(根据自己能力选做,以完成上述功能为主)
    本次作业我与李朝帅同学合作,我为驾驶员,他为领航员,代码已上传至coding.net

二 功能设计

1 功能分析

经过审题,我和李朝帅同学决定实现以下功能:

  • 题目数量任意选择;
  • 运算符可选+、-、*、/、中的一个或多个;
  • 最大数值有三档可选,分别为:十以内、一百以内、一千以内;
  • 运算中仅存在小括号,不错在中括号及大括号,小数可到小数点后两位;
  • 算式为由3到9个数字四则混合运算;
  • 可选择输出到文件;
  • 由于时间关系以及我们的能力关系,图形用户界面无法实现,后期会加以补充。

2 关键部分代码简述

(1) 表达式的生成

我采用随机数r = rand() % 7 + 2来控制表达式的长度,在一次循环里仅输出一个数字并且用随机数x = rand() % 5选择一个运算符,部分代码如下。
输出数字(以输出小数为例):


printf("%.2f", rand() / (double)(RAND_MAX / h));
if (a[4] == 1)
{
    if ((fp = fopen("aa.txt", "a")) == NULL)    //将表达式写入到文件
    {
        printf("不能打开文件!\n");
        exit(0);
    }
fprintf(fp, "%.2f", rand() / (double)(RAND_MAX / h));
fclose(fp);
}

输出运算符(以输出+为例):


case 1:
if (a[0] == 1)
{
printf(" + ");
    if (a[4] == 1)
    {
    if ((fp = fopen("aa.txt", "a")) == NULL)    //将表达式写入到文件
    {
        printf("不能打开文件!\n");
        exit(0);
    }
    fprintf(fp, " + ");
    fclose(fp);
    }
break;
}

(2) 括号的生成

使用随机数在数字前产生左括号,在数字后产生右括号,并使用两个变量flagflag1来控制括号的匹配以及括号中无运算符的情况,部分代码如下。
左括号:

if (k == 1 && flag2 == 0 && rand() % 2 == 1)
{
    printf(" ( ");
    if (a[4] == 1)
    {
        if ((fp = fopen("aa.txt", "a")) == NULL)    //将表达式写入到文件
        {
            printf("不能打开文件!\n");
            exit(0);
        }
        fprintf(fp, " ( ");
        fclose(fp);
    }
flag2 = 1;
flag1 = 1;
}

右括号:


if (k == 1 && flag2 == 1 && rand() % 2 == 1 && flag1 != 1)
{
printf(" ) ");
    if (a[4] == 1)
    {
        if ((fp = fopen("aa.txt", "a")) == NULL)    //将表达式写入到文件
        {
            printf("不能打开文件!\n");
            exit(0);
        }
        fprintf(fp, " ) ");
        fclose(fp);
    }
    flag2 = 0;
}
flag1 = 0;

三 运行结果

使用带有括号的小数四则运算来演示,结果如下:

输出文件如下:

四 对领航员的评价

在这次的作业中,作业的难度本身并不算大,程序也不算复杂,但是结对编程的思想还是第一次接触,李朝帅将驾驶员的任务交给我,自己选择了较为陌生的领航员,身为领航员的李朝帅同学尽职尽责,在我们设计功能需求的时候,他帮我明确了我们需要完成的功能,并且在后续编码过程中也给我提供了很大的帮助,这个程序的最初版本有很多的功能并未实现,而且还有很多的bug,比如:无法加减乘除同时运算,没有实现小数的运算等...李朝帅同学都为我一一指出,我在此基础上加以改进才有了我们的最终的版本。
在后续的单元测试以及代码复审中李朝帅同学也是及时完成,并对我的代码进行了中肯的评价的同时找出了程序很多的小缺陷。    
总的来说,李朝帅非常完美的履行了一个领航员的指责,让我可以安心的面对前方的赛道。

五 总结

通过这次的作业,我们练习了之前从未接触过的结对编程(领航员-驾驶员)的思想,我是驾驶员,主要负责代码的编写,我的搭档李朝帅为领航员,负责单元测试以及代码的复审。领航员驾驶员这两个名词我并不陌生,很多看过赛车的小伙伴也一定很熟悉,赛车行驶在崎岖的赛道上,驾驶员意识集中在前方赛道上,领航员提醒着他路况的变化,赛车的状态。两人互相配合,相辅相成才能取得冠军。虽然我没有开过赛车,但是通过这次的作业我体验到了赛车场上两人无间的配合,我原以为赛道上驾驶员才是最高光的存在,但是现在我发现了有一个好的领航员才能成就伟大的驾驶员,领航员李朝帅给我提建议,帮我寻找程序中存在的缺陷,没有好的领航员,驾驶员根本无法完成一圈的赛道!
因为时间原因以及我个人的水平原因,这次作业我们没有实现图形化界面,但是后期我们会加以补充,总的来说,这次的作业让我们受益匪浅,不仅学到了结对开发的技术,还找到了我自身的不足,以后有机会我还会跟李朝帅同学合作,并且尝试当领航员的感觉。