结对项目——自动生成小学四则运算题目
一、Github项目地址
地址: https://github.com/Sheaxx/Myapp
结对成员:18软4方晓莹 3218005126 ,18软4黄芯悦 3218005128
二、项目概况
项目说明
自然数:0, 1, 2, …。
- 真分数:1/2, 1/3, 2/3, 1/4, 1’1/2, …。
- 运算符:+, −, ×, ÷。
- 括号:(, )。
- 等号:=。
- 分隔符:空格(用于四则运算符和等号前后)。
- 算术表达式:
e = n | e1 + e2 | e1 − e2 | e1 × e2 | e1 ÷ e2 | (e),
其中e, e1和e2为表达式,n为自然数或真分数。
- 四则运算题目:e = ,其中e为算术表达式。
项目需求
1. 使用 -n 参数控制生成题目的个数。(实现)
例如: Myapp.exe -n 10
//将生成10个题目。
2. 使用 -r 参数控制题目中数值(自然数、真分数和真分数分母)的范围。(实现)
例如: Myapp.exe -r 10
//将生成10以内(不包括10)的四则运算题目。
//该参数可以设置为1或其他自然数。
//该参数必须给定,否则程序报错并给出帮助信息。
3. 生成的题目中计算过程不能产生负数。(实现)
也就是说算术表达式中如果存在形如e1− e2的子表达式,那么e1≥ e2。
4. 生成的题目中如果存在形如 e1÷ e2 的子表达式,那么其结果应是真分数。(实现)
5. 每道题目中出现的运算符个数不超过3个。(实现)
6. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一
道题目。
(未完全实现,仅实现排除完全重复的题目)
例如:
① 23 + 45 = 和45 + 23 = 是重复的题目。
② 6 × 8 = 和8 × 6 = 也是重复的题目。
③ 3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就
是3+(2+1)。
④ 但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过
有限次交换变成同一个题目。
7. 生成的题目存入执行程序的当前目录下的Exercises.txt文件。(实现)
格式如下:
- 四则运算题目1
- 四则运算题目2
……
其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。
8. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件。(实现)
格式如下:
- 答案1
- 答案2
……
特别的,真分数的运算如下例所示:1/6 + 1/8 = 7/24。
9. 程序应能支持一万道题目的生成。(实现)
10. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。(实现)
输入参数:Myapp.exe -e <exercisefile>.txt -a <answerfile>.txt
统计结果输出到文件Grade.txt,格式如下:
Correct: 5 (1, 3, 5, 7, 9)
Wrong: 5 (2, 4, 6, 8, 10)
其中“:”后面的数字5表示对/错的题目的数量,括号内的是对/错题目的编号。为简单起见,假设输入的题目
都是按照顺序编号的符合规范的题目。
三、PSP表格
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
||
· Estimate |
· 估计这个任务需要多少时间 |
600+650 |
480+550 |
Development |
开发 |
||
· Analysis |
· 需求分析 (包括学习新技术) |
60+50 |
50+50 |
· Design Spec |
· 生成设计文档 |
30+30 |
25+25 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
30+30 |
20+20 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
10+10 |
10+10 |
· Design |
· 具体设计 |
60+55 |
80+70 |
· Coding |
· 具体编码 |
480+500 |
520+550 |
· Code Review |
· 代码复审 |
40+45 |
30+35 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
60+60 |
80+75 |
Reporting |
报告 |
||
· Test Report |
· 测试报告 |
40+40 |
30+30 |
· Size Measurement |
· 计算工作量 |
10+10 |
10+10 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
10+10 |
10+10 |
合计 |
1430+1490 |
1345+1435 |
四、效能分析
改进思路
1. 化简计算:一开始选择把整数和分数的计算分为两个函数,后来经过讨论,发现整数和分数的计算其实是一致的,前者是分母为1的情况,后者是分母不为0且不为1的情况。基于讨论,合并了两个函数,并化简了计算过程。
2. 模块化:整个项目中有很多部分都是重复调用的,比如分数化简、获取随机数、生成运算数等,将重复调用的内容独立出一个函数,作为接口在需要的地方调用,实现了模块化的思想。
3. 需求分析:两人讨论在讨论需求时,认识到程序的实现过程其实和需求10是互逆的。由此,根据我们的实现过程,反向实现需求10。
性能分析
对生成1W题的情况进行了相关的性能分析,如下图所示:
函数展示
以下是消耗最大的函数代码展示:
1 //运算菜单 2 void menu(int n,int r,char str1[],char str2[],bool flag) { 3 FILE* fp1, * fp2, * fp3, * fp4, * fp5; 4 errno_t err1, err2, err3, err4, err5; 5 int select = 0, select1 = 0; //随机选定分数或整数运算 6 int i = 0, j = 0, k = 0, m = 0, p = 0, x = 0, a = 0; 7 int y1 = 0, y2 = 0, y3 = 0; //打印判定结果的参数 8 int mark = 0, tab = 0; //分数和括号的判定标记 9 int mo[4] = { 0 }; 10 int mi = 0; 11 int num[7] = { 0 }, t[8] = { 0 }; 12 int c[100] = { 0 }, w[100] = { 0 }; 13 char s[10] = { '\0' }; //存放运算符 14 char ef[100] = { '\0' }; //存放题目 15 char af[20] = { '\0' }; //存放答案 16 char cmp[20] = { '\0' }; 17 char grade[10] = { '\0' }; 18 err1 = fopen_s(&fp1, "Exercises.txt", "w+"); 19 err2 = fopen_s(&fp2, "Answers.txt", "w+"); 20 err3 = fopen_s(&fp3, str1, "r"); 21 err4 = fopen_s(&fp4, str2, "r"); 22 err5 = fopen_s(&fp5, "Grade.txt", "w+"); 23 24 srand((unsigned long)time(0)); 25 26 if (fp1 == NULL || fp2 == NULL) { 27 printf("文件不存在。\n"); 28 } 29 else if (fp3 != NULL && fp4 != NULL && flag == false) { 30 //获取题目和答案 31 while (fgets(ef, sizeof(ef) - 1, fp3) && fgets(af, sizeof(af) - 1, fp4)) { 32 j = 0; k = 0; m = 0; p = 0; tab = 0; mark = 0; //初始化 33 while (j >= '0' && j <= '9') j++; 34 j += 4; //指到序号后的数字的第一位 35 for (; j < strlen(ef); j++) { 36 if (ef[j] >= '0' && ef[j] <= '9') { 37 if (mark == 0 || mark == 1) { 38 mi = ef[j] - 48; 39 t[k] = t[k] * 10 + mi; 40 if (ef[j + 1] == ' ' || ef[j + 1] == '\n' || ef[j + 1] == '\0' || ef[j + 1] == ')') { 41 if (mark == 0)t[++k] = 1; //说明是整数,分母置为1 42 else mark = 0; //说明分母的数字结束 43 k++; 44 if (k % 2 == 0 && k != 0)p++; //储存分子的数组指向下一位 45 } 46 else if (ef[j + 1] == '/') { //分子数字结束 47 mark = 1; 48 k++; 49 } 50 else if (ef[j + 1] == 39)mark = 2; //带分数 51 } 52 else if (mark == 2) { 53 mi = ef[j] - 48; 54 mo[p] = 10 * mo[p] + mi; 55 if (ef[j + 1] == '/') { //带分数分子数字结束 56 k++; 57 mark = 1; 58 } 59 } 60 } 61 else if ((ef[j] == '+' || ef[j] == '-' || ef[j] == '*' || ef[j] == '/') && ef[j + 1] == ' ') { 62 s[m++] = ef[j]; 63 } 64 else if (ef[j] == '(') { 65 if (k == 0)tab = 1; //第一个数之前的括号 66 else if (k == 2)tab = 2; //第二个数之前的括号 67 } 68 } 69 70 for (m = 0, p = 0; m < k - 1; m += 2, p++) { 71 if (mo[p] != 0)t[m] = t[m] * t[m + 1] + mo[p]; 72 }//带分数变成假分数 整数部分乘分母加上分子 73 74 if (tab == 0) { 75 //无括号 76 if (k == 4) select = 0; 77 else if (k == 6) { 78 select = 1; 79 a = 3; 80 } 81 else if (k == 8) select = 2; 82 } 83 else if (tab == 1) { 84 //3个运算数,前括 85 select = 1; 86 a = 1; 87 } 88 else if (tab == 2) { 89 //3个运算数,后括 90 select = 1; 91 a = 2; 92 } 93 94 num[0] = order(s, select, a); 95 digit_integer(i + 1, cmp, y3); 96 //拼接序号 97 cmp[y3++] = '.'; 98 cmp[y3++] = ' '; 99 cmp[y3++] = ' '; 100 cmp[y3++] = '\0'; 101 cmp[strlen(cmp)] = '\0'; 102 strcat_s(cmp, 20, classify(num, t, s, r, i, fp1, fp2, flag)); 103 y3 = strlen(cmp); 104 cmp[y3] = '\n'; //换行符结尾 105 cmp[++y3] = '\0'; //数组结尾 106 if (strcmp(af, cmp) == 0)c[y1++] = i + 1; 107 else w[y2++] = i + 1; 108 for (j = 0; j < 8; j++) t[j] = 0; 109 for (j = 0; j < 4; j++) mo[j] = 0; 110 for (j = 0; j < 10; j++) s[j] = '\0'; 111 y3 = 0; 112 i++; 113 } 114 fclose(fp3); 115 fclose(fp4); 116 117 //打印正确结果 118 printf("\nCorrect: %d (", y1); 119 for (y3 = 0; y3 < y1 - 1; y3++) 120 printf("%d,", c[y3]); 121 printf("%d)\n", c[y3]); 122 123 //打印错误结果 124 printf("Wrong: %d (", y2); 125 for (y3 = 0; y3 < y2 - 1; y3++) 126 printf("%d,", w[y3]); 127 printf("%d)\n", w[y3]); 128 129 printf("\n判定完成!判定结果已存入Grade.txt中。\n"); 130 131 j = 0; 132 fputs("Correct: ", fp5); 133 digit_integer(y1, grade, j); 134 fputs(grade, fp5); 135 fputs(" (", fp5); 136 for (y3 = 0; y3 <= y1 - 1; y3++) { 137 j = 0; 138 digit_integer(c[y3], grade, j); 139 fputs(grade, fp5); 140 if (y3 + 1 != y1)fputs(",", fp5); 141 } 142 if (c[0] == 0)fputs("0", fp5); 143 fputs(")\n", fp5); 144 145 j = 0; 146 fputs("Wrong: ", fp5); 147 digit_integer(y2, grade, j); 148 fputs(grade, fp5); 149 fputs(" (", fp5); 150 for (y3 = 0; y3 <= y2 - 1; y3++) { 151 j = 0; 152 digit_integer(w[y3], grade, j); 153 fputs(grade, fp5); 154 if (y3 + 1 != y2)fputs(",", fp5); 155 } 156 if (w[0] == 0)fputs("0", fp5); 157 fputs(")\n", fp5); 158 } 159 else if ((fp3 == NULL || fp4 == NULL) && flag == false) { 160 printf("未找到指定文件。\n"); 161 } 162 else { 163 while (i < n) { 164 select1 = rand() % 30; 165 num[0] = numcreate(t, select1 % 3, r, s); //随机生成数 166 strcpy_s(cmp, classify(num, t, s, r, i, fp1, fp2, flag)); 167 if (strcmp(cmp, "-1") == 0) continue; 168 else i++; 169 } 170 printf("\n成功生成%d道四则运算题,题目和答案已存入Exercises.txt和Answers.txt中。\n", n); 171 fclose(fp1); 172 fclose(fp2); 173 } 174 }
五、设计实现过程
六、代码说明
此处展示了运算情况的分析、加减乘除的实现和整数除法共三段关键代码。
1 //分析运算情况并写入文件 2 char* classify(int num[], int t[], char s[], int r, int i, FILE* fp1, FILE* fp2,bool flag) { 3 int j = 0, k = 0, m = 0, x = 0, l = 0; 4 int tag = 1; //tag=1是第一个数,tag=2是后边的数,tag=3是答案 5 int num1[7] = { 0 }; 6 int str[3] = { 0 }; //暂时存放分数的三部分 7 char c[10] = { '\0' }; //序号 8 char e[100] = { '\0' }; //题目 9 char e1[50] = { '\0' }, e2[50] = { '\0' }; //有括号的拼接式 10 char a[20] = { '\0' }; //答案 11 char wrong[5] = "-1"; 12 13 if (num[0] == 0) { //两个运算数 14 while (j < 4) { 15 num[j + 1] = t[j]; 16 j++; 17 } 18 if (arithmetic_fraction(num, s[0], r, tag, e, k, str) == -1) 19 return wrong; 20 } 21 else if (num[0] == 1 || num[0] == 3) { //三个运算数 按顺序从左到右运算 22 while (j < 4) { 23 num[j + 1] = t[j]; 24 j++; 25 } 26 if (num[0] == 1) { 27 e[k++] = '('; 28 } 29 if (arithmetic_fraction(num, s[0], r, tag, e, k, str) == -1) 30 return wrong; 31 num[1] = num[5]; 32 num[2] = num[6]; 33 num[3] = t[4]; 34 num[4] = t[5]; 35 tag = 2; 36 if (num[0] == 1) { 37 e[k++] = ')'; 38 } 39 if (arithmetic_fraction(num, s[1], r, tag, e, k, str) == -1) 40 return wrong; 41 } 42 else if (num[0] == 2 || num[0] == 5) { //三个运算数 右边两个数先运算 43 j = 1; 44 while (j < 5) { 45 num[j] = t[j + 1]; 46 j++; 47 } 48 e1[k++] = '('; 49 if (arithmetic_fraction(num, s[1], r, tag, e1, k, str) == -1) 50 return wrong; 51 e1[k++] = ')'; 52 e1[k] = '\0'; 53 num[1] = t[0]; 54 num[2] = t[1]; 55 num[3] = num[5]; 56 num[4] = num[6]; 57 tag = 1; 58 k = 0; 59 l = arithmetic_fraction(num, s[0], r, tag, e, k, str); 60 if (l == -1)return wrong; 61 e[l] = '\0'; 62 strcat_s(e, e1); 63 l = strlen(e); 64 e[l] = '\0'; 65 } 66 else if (num[0] == 6) { //四个运算数 按顺序运算 67 while (j < 4) { 68 num[j + 1] = t[j]; 69 j++; 70 } 71 if (arithmetic_fraction(num, s[0], r, tag, e, k, str) == -1) 72 return wrong; 73 num[1] = num[5]; 74 num[2] = num[6]; 75 num[3] = t[4]; 76 num[4] = t[5]; 77 tag = 2; 78 if (arithmetic_fraction(num, s[1], r, tag, e, k, str) == -1) 79 return wrong; 80 num[1] = num[5]; 81 num[2] = num[6]; 82 num[3] = t[6]; 83 num[4] = t[7]; 84 tag = 2; 85 if (arithmetic_fraction(num, s[2], r, tag, e, k, str) == -1) 86 return wrong; 87 } 88 else if (num[0] == 7) { //四个运算数 先算中间两个数 89 j = 1; 90 while (j < 5) { 91 num[j] = t[j + 1]; 92 j++; 93 } 94 if (arithmetic_fraction(num, s[1], r, tag, e1, k, str) == -1) 95 return wrong; 96 num[1] = t[0]; 97 num[2] = t[1]; 98 num[3] = num[5]; 99 num[4] = num[6]; 100 tag = 1; 101 k = 0; 102 l = arithmetic_fraction(num, s[0], r, tag, e, k, str); 103 if (l == -1)return wrong; 104 e[l] = '\0'; 105 strcat_s(e, e1); 106 k = l = strlen(e); 107 e[l] = '\0'; 108 num[1] = num[5]; 109 num[2] = num[6]; 110 num[3] = t[6]; 111 num[4] = t[7]; 112 tag = 2; 113 l = arithmetic_fraction(num, s[2], r, tag, e, k, str); 114 if (l == -1)return wrong; 115 e[k] = '\0'; 116 } 117 else if (num[0] == 8 || num[0] == 10) { //四个运算数 先算前后 再中间运算 118 while (j < 4) { 119 num1[j + 1] = t[j]; 120 j++; 121 } 122 j = 1; 123 while (j < 5) { 124 num[j] = t[j + 3]; 125 j++; 126 } 127 l = arithmetic_fraction(num1, s[0], r, tag, e1, k, str); 128 if (l == -1)return wrong; 129 k = 0; 130 tag = 1; 131 l = arithmetic_fraction(num, s[2], r, tag, e2, k, str); 132 if (l == -1)return wrong; 133 e[0] = '\0'; 134 strcat_s(e, e1); 135 k = strlen(e); 136 signstrcat(s[1], e, k); 137 strcat_s(e, e2); 138 num[1] = num1[5]; 139 num[2] = num1[6]; 140 num[3] = num[5]; 141 num[4] = num[6]; 142 k = 0; 143 tag = 2; 144 l = arithmetic_fraction(num, s[1], r, tag, e1, k, str); 145 if (l == -1)return wrong; 146 } 147 else if (num[0] == 9) { //四个运算数 先算后面三个数 148 j = 1; 149 while (j < 5) { 150 num[j] = t[j + 1]; 151 j++; 152 } 153 l = arithmetic_fraction(num, s[1], r, tag, e1, k, str); 154 if (l == -1)return wrong; 155 num[1] = num[5]; 156 num[2] = num[6]; 157 num[3] = t[6]; 158 num[4] = t[7]; 159 tag = 2; 160 l = arithmetic_fraction(num, s[2], r, tag, e1, k, str); 161 if (l == -1)return wrong; 162 num[1] = t[0]; 163 num[2] = t[1]; 164 num[3] = num[5]; 165 num[4] = num[6]; 166 k = 0; 167 tag = 1; 168 l = arithmetic_fraction(num, s[0], r, tag, e, k, str); 169 if (l == -1)return wrong; 170 e[l] = '\0'; 171 strcat_s(e, e1); 172 } 173 if (flag == true) { //如果是检查文件的运算结果 不用查重 174 if (repeat(e) == -1)return wrong; 175 else { 176 strcpy_s(list[se], 50, e); 177 se++; 178 } 179 } 180 181 printf("%d. ", i + 1); //打印序号 182 printf("%s", e); //打印题目 183 digit_integer(i + 1, c, x); 184 strcat_s(c, ". "); //序号拼接 185 186 //打印结果 187 if (str[0] == 0 && str[1] == 0) { 188 digit_integer(0, a, m); 189 printf(" = 0\n"); 190 } 191 else if (str[0] != 0 && str[1] == 0) { 192 digit_integer(str[0], a, m); 193 printf(" = %d\n", str[0]); 194 } 195 else if (str[0] == 0 && str[1] != 0) { 196 digit_integer(str[1], a, m); 197 a[m++] = '/'; 198 digit_integer(str[2], a, m); 199 printf(" = %d/%d\n", str[1], str[2]); 200 } 201 else { 202 digit_integer(str[0], a, m); 203 a[m++] = 39;//39是'的ASCII码 204 digit_integer(str[1], a, m); 205 a[m++] = '/'; 206 digit_integer(str[2], a, m); 207 printf(" = %d'%d/%d\n", str[0], str[1], str[2]); 208 } 209 210 fputs(c, fp1); 211 fputs(c, fp2); //写入序号 212 fputs(e, fp1); //写入题目 213 fputs(a, fp2); //写入答案 214 fputc('\n', fp1); 215 fputc('\n', fp2); 216 217 return a; 218 }
1 //运算数的加减乘除函数 2 int arithmetic_fraction(int num[], char sign, int r, int& tag, char e[], int& k, int str[]) { 3 int x = 0; 4 5 if (sign == '-') { 6 //对减的情况做判断,减数小于被减数则返回-1,不打印该式子 7 if (num[1] * num[4] - num[2] * num[3] < 0) return -1; 8 } 9 10 //被除数为0则返回-1,不打印该式子 11 if (sign == '/' && num[3] == 0) return -1; 12 13 //第一个运算数 14 if (tag == 1) division_integer(num[1], num[2], tag, e, k, str); 15 tag = 2; 16 signstrcat(sign, e, k); 17 x = k; 18 //第二个运算数 19 division_integer(num[3], num[4], tag, e, k, str); 20 21 //运算过程 22 if (sign == '+') { 23 num[5] = num[1] * num[4] + num[3] * num[2]; 24 num[6] = num[2] * num[4]; 25 tag = 3; 26 division_integer(num[5], num[6], tag, e, k, str); 27 } 28 else if (sign == '-') { 29 num[5] = num[1] * num[4] - num[3] * num[2]; 30 num[6] = num[2] * num[4]; 31 tag = 3; 32 division_integer(num[5], num[6], tag, e, k, str); 33 } 34 else if (sign == '*') { 35 num[5] = num[1] * num[3]; 36 num[6] = num[2] * num[4]; 37 tag = 3; 38 division_integer(num[5], num[6], tag, e, k, str); 39 } 40 else if (sign == '/') { 41 num[5] = num[1] * num[4]; 42 num[6] = num[2] * num[3]; 43 tag = 3; 44 division_integer(num[5], num[6], tag, e, k, str); 45 } 46 return x; 47 }
1 //整数除法的函数(判断分数是真分数、假分数、整数、0,并化简打印式子) 2 char division_integer(int& numA, int& numB, int tag, char e[], int& k, int str[]) { 3 //余数和倍数 4 int multiple = 0, remainder = 0; 5 int* p1 = &multiple, * p2 = &remainder; 6 //最大公因数 7 int max = max_common(numA, numB); 8 9 //tag=1为第一个运算数,tag=2为其他运算数,tag=3为答案 10 //被除数为0,除法不存在 11 if (numB == 0) return -1; 12 //分子为0或分母为1 13 else if (numA == 0 || numB == 1) { 14 if (tag == 1) { 15 digit_integer(numA, e, k); 16 } 17 else if (tag == 2) { 18 digit_integer(numA / numB, e, k); 19 } 20 else if (tag == 3) { 21 if (numA == 0) { 22 str[0] = 0; 23 str[1] = 0; 24 } 25 else { 26 str[0] = numA; 27 str[1] = 0; 28 } 29 } 30 return 0; 31 } 32 //判断余数,能整除则返回除法答案 33 else if (numA % numB == 0) { 34 if (tag == 1) { 35 digit_integer(numA / numB, e, k); 36 } 37 else if (tag == 2) { 38 digit_integer(numA / numB, e, k); 39 } 40 else if (tag == 3) { 41 str[0] = numA / numB; str[1] = 0; 42 } 43 return numA / numB; 44 } 45 //分子大于分母,是假分数,先化简再化为带分数,返回1 46 else if (numA > numB) { 47 //最大公因数为1,无需化简 48 if (max != 1) { 49 numA = numA / max; 50 numB = numB / max; 51 } 52 change(numA, numB, p1, p2); 53 if (tag == 1) { 54 digit_integer(*p1, e, k); 55 e[k++] = 39; 56 digit_integer(*p2, e, k); 57 e[k++] = '/'; 58 digit_integer(numB, e, k); 59 } 60 else if (tag == 2) { 61 digit_integer(*p1, e, k); 62 e[k++] = 39; 63 digit_integer(*p2, e, k); 64 e[k++] = '/'; 65 digit_integer(numB, e, k); 66 } 67 else if (tag == 3) { 68 str[0] = *p1; str[1] = *p2; str[2] = numB; 69 } 70 return 1; 71 } 72 //分子小于分母,是真分数,只需要化简,返回2 73 else if (numA < numB) { 74 //最大公因数为1 75 if (max != 1) { 76 numA = numA / max; 77 numB = numB / max; 78 } 79 if (tag == 1) { 80 digit_integer(numA, e, k); 81 e[k++] = '/'; 82 digit_integer(numB, e, k); 83 } 84 else if (tag == 2) { 85 digit_integer(numA, e, k); 86 e[k++] = '/'; 87 digit_integer(numB, e, k); 88 } 89 else if (tag == 3) { 90 str[0] = 0; str[1] = numA; str[2] = numB; 91 } 92 return 2; 93 } 94 }
七、测试运行
未输入某些参数,程序会报错,并给出帮助信息
按要求输入参数后,程序会打印题目,并将题目和答案分别存入文件。
生成10道题
生成100道题
生成1000道题
生成10000道题(附文件图)
程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计。
给定10道题(附文件图)
10道题中修改1、5、8题的答案
判定结果如下
八、项目小结
总结教训
1. 要在写项目之前构造好整体框架思路。本次项目的开发,中途出现了多次前后思路冲突,导致产生了一些很难找到的bug,花费了很多的时间。
2. 本次采用了C语言开发此项目,感觉较为繁琐,但两人对C语言都较为熟悉,在开发过程中还算顺利。
3. 本项目中的查重需求,两人讨论了很久并且上网查询了相关资料,但没有拿出一个很好的、较简化的思路和方案。加之一开始做的时候并没有想到用相关的存储结构存储数据,导致在后边想实现查重需求就变得非常繁琐,再重复用存储结构存储时非常不便,所以并未完整实现该需求。
4. 在整个开发过程中,要及时和队友交流想法和成果,以确保能够互相配合编写代码完成项目。
结对情况
本次结对项目使用github管理代码,两人各开一个分支,在完成相应的功能后将自己的分支合并到master分支,供队友获取最新代码。
结对感受
1. 遇到问题,能和队友讨论,在讨论的过程中两人互相提出质疑和建议,感受比百度好用多了!
2. 通过结对,学习到了队友身上的一些思路和经验,感觉更好的完善了自己的开发思路和框架。
3. 当自己写的代码找不到bug出处时,和队友一起研究讨论是个很好的解决方法。
闪光点/建议/分享
To 芯悦:
经常会对自己写的代码做化简,也会对我的代码提出建议,来简化整个项目的开发。这种思考值得我多加学习和总结。
To 晓莹:
很有耐心,遇到问题会认真琢磨。经常会和我分享讨论想法来解决问题,在整个项目开发过程中帮助了我很多。