一、Github与源代码
https://github.com/wuchengttt/hello-world
源代码
主函数
int main() { //检测是否存在这两个文件,如果没有就新建 FILE *fp; fp = fopen("Exercises.txt", "w+"); fclose(fp); fp = fopen("Answers.txt", "w+"); fclose(fp); int range = 0; printf("请输入产生几以内的数字:"); scanf_s("%d", &range); printf("\n请输入产生多少个运算表达式:"); scanf_s("%d", &num); int right1 = 0; int wrong1 = 0; char(*result)[LENGTH] = (char(*)[LENGTH])malloc(sizeof(char)*LENGTH*num); int i; for (i = 1; i <= num; i++) {//随机生成四个数字 //char expArr[2];//定义生成的题目 int a = (int)(random(range));//分子 int b = (int)(random(range));//分母 int c = (int)(random(range));//另一个分子 int d = (int)(random(range));//另一个分母 int fuhao;//运算符 fuhao = (int)(random(4)); product_exp(a, b, c, d, fuhao, i, *result + i);//进入处理函数 } free(result); printf("\n回答完成请按回车"); getchar(); getchar(); check1(); system("pause"); return 0; }
主函数创建txt文本,并且调用生成表达式函数,最后可以进行答案检查
整数型转字符型函数
void myitoa(int num_i, char *str) { int j = 0, i = 0; char number[10] = { ‘0‘,‘1‘,‘2‘,‘3‘,‘4‘,‘5‘,‘6‘,‘7‘,‘8‘,‘9‘ }; char temp[10] = { 0 }; while (num_i != 0) { temp[i] = number[num_i % 10]; i++; num_i = num_i / 10; } temp[i] = ‘\0‘; i = i - 1; while (i >= 0) { str[j] = temp[i]; j++; i--; } str[j] = ‘\0‘; //printf("%s", str); }
随机数函数
int random(int a) {//随机数 int b; b = rand() % a + 1; return b; }
生成算术函数
void product_exp(int a, int b, int c, int d, int fuhao, int y, char *result) { int fenzi; int fenmu; char*ab = biaodashi(a, b); char*cd = biaodashi(c, d); FILE *fp; FILE *fp1; fp = fopen("Exercises.txt", "a"); fp1 = fopen("Answers.txt", "a"); if (b != 0 && d != 0) { switch (fuhao) { case 1: fenzi = a * d + b * c; fenmu = b * d; fprintf(fp, "%d:%s + ", y, biaodashi(a, b)); fprintf(fp, "%s = \n", biaodashi(c, d)); fprintf(fp1, "%d:%s\n", y, yuefen(fenzi, fenmu)); break; case 2: if (a*d - b * c >= 0) { fenzi = a * d - b * c; fenmu = b * d; fprintf(fp, "%d:%s - ", y, biaodashi(a, b)); fprintf(fp, "%s = \n", biaodashi(c, d)); fprintf(fp1, "%d:%s\n", y, yuefen(fenzi, fenmu)); } else { fenzi = b * c - a * d; fenmu = b * d; fprintf(fp, "%d:%s - ", y, biaodashi(c, d)); fprintf(fp, "%s = \n", biaodashi(a, b)); fprintf(fp1, "%d:%s\n", y, yuefen(fenzi, fenmu)); } break; case 3: fenzi = a * c; fenmu = b * d; fprintf(fp, "%d:%s × ", y, biaodashi(a, b)); fprintf(fp, "%s = \n", biaodashi(c, d)); fprintf(fp1, "%d:%s\n", y, yuefen(fenzi, fenmu)); break; case 4: if (c != 0) { fenzi = a * d; fenmu = b * c; fprintf(fp, "%d:%s ÷ ", y, biaodashi(a, b)); fprintf(fp, "%s = \n", biaodashi(c, d)); fprintf(fp1, "%d:%s\n", y, yuefen(fenzi, fenmu)); break; } else break; default: break; } fclose(fp); fclose(fp1); } }
约分函数
char* yuefen(int a, int b) { static char str[10] = { 0 }; for (int k = 0; k < 10; k++) //for循环初始化 { str[k] = 0; } int y = 1; char c_z[LENGTH] = { 0 }; for (int i = a; i >= 1; i--) { if (a%i == 0 && b%i == 0) { y = i; break; } } int z = a / y; int m = b / y; if (a == 0) { str[0] = ‘0‘; return str; } if (m == 1) { myitoa(z, c_z); strcat(str, c_z); return str; } else return biaodashi(z, m); }
对算术结果进行约分后放入答案文本中
表达式规范函数
char* biaodashi(int a, int b) { static char str[LENGTH] = { 0 }; for (int k = 0; k < LENGTH; k++) //for循环初始化 { str[k] = 0; } char c_a[LENGTH] = { 0 }; char c_c[LENGTH] = { 0 }; char c_b[LENGTH] = { 0 }; char c_d[LENGTH] = { 0 }; myitoa(a, c_a); //int转为char myitoa(b, c_b); if (a >= b) { int c; c = a / b; int d; d = a % b; myitoa(c, c_c); myitoa(d, c_d); { if (d == 0) { strcat(str, c_c); return str; } strcat(str, c_c); strcat(str, "\‘"); strcat(str, c_d); strcat(str, "\/"); strcat(str, c_b); return str; } } strcat(str, c_a); strcat(str, "\/"); strcat(str, c_b); return str; }
检查答案函数:
int check1() { FILE *fp0; fp0 = fopen("Grade.txt", "w+"); FILE *fp; FILE *fp1; int i = 0, j = 0, t = 0, w = 0, r = 0, l = 0, h = 0; int * rightcount = (int*)malloc((num + 2) * sizeof(int)); memset(rightcount, -1, sizeof(rightcount)); int * wrongcount = (int*)malloc((num + 2) * sizeof(int)); memset(wrongcount, -1, sizeof(wrongcount)); char StrLine[10] = {}; //每个答案最大读取的字符数 char StrLine1[10] = {}; if ((fp = fopen("Exercises.txt", "r")) == NULL) //判断文件是否存在及可读 { printf("Exercises.txt error!"); return -1; } if ((fp1 = fopen("Answers.txt", "r")) == NULL) //判断文件是否存在及可读 { printf("Answers.txt error!"); return -1; } char ch_Q = 0; char ch_A = 0; for (t = 1; t <= num; t++) {//一行 ch_Q = fgetc(fp); if (ch_Q != EOF) { while (ch_Q != ‘\n‘) {//题目 if (ch_Q == ‘=‘) { ch_Q = fgetc(fp); for (i = 0; ch_Q != ‘\n‘; i++) { ch_Q = fgetc(fp); StrLine[i] = ch_Q; } StrLine[i] = ‘\0‘; ch_A = fgetc(fp1); if (ch_A != EOF) while (ch_A != ‘\n‘) { if (ch_A == ‘:‘) {//答案 for (j = 0; ch_A != ‘\n‘; j++) { ch_A = fgetc(fp1); StrLine1[j] = ch_A; } StrLine1[j] = ‘\0‘; } else ch_A = fgetc(fp1); } } else ch_Q = fgetc(fp); } } for (int a = 0; StrLine1[a] != ‘\n‘; a++) { if (StrLine[a] != StrLine1[a]) { w++; wrongcount[l] = t;//记录错的题号 l++; wrongcount[l] = ‘\0‘; break; } else { if (StrLine[a + 1] == ‘\n‘ && StrLine1[a + 1] == ‘\n‘) { r++; rightcount[h] = t; //记录对的题号 h++; rightcount[h] = ‘\0‘; break; } } } } fprintf(fp0, "Correct: %d (", r); for (int g = 0; rightcount[g] != ‘\0‘; g++) fprintf(fp0, "%d ", rightcount[g]); fprintf(fp0, ")\n"); fprintf(fp0, "Wrong: %d (", w); for (int g = 0; wrongcount[g] != ‘\0‘; g++) fprintf(fp0, "%d ", wrongcount[g]); fprintf(fp0, ")\n"); fclose(fp0); fclose(fp); fclose(fp1); //关闭文件 free(rightcount); free(wrongcount); return 0; }
二、PSP
PSP2.1 |
Personal Software Process Stages |
预估耗时(分钟) |
实际耗时(分钟) |
Planning |
计划 |
30 |
25 |
· Estimate |
· 估计这个任务需要多少时间 |
30
|
25 |
Development |
开发 |
2310 |
2140 |
· Analysis |
· 需求分析 (包括学习新技术) |
240 |
200 |
· Design Spec |
· 生成设计文档 |
120 |
60 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
360 |
60 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
30 |
20 |
· Design |
· 具体设计 |
120 |
120 |
· Coding |
· 具体编码 |
720 |
960 |
· Code Review |
· 代码复审 |
360 |
360 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
360 |
360 |
Reporting |
报告 |
90 |
90 |
· Test Report |
· 测试报告 |
30 |
30 |
· Size Measurement |
· 计算工作量 |
30 |
30 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 |
30 |
合计 |
|
2430 |
2255 |
三、效能分析和覆盖率测试
使用vs2017自带的性能探测器进行i效能分析,如下图
通过两张图,我们能发现,主函数占用了6成的时间,而子函数product_exp占用3成,检查函数不到一成,原因是我们含有一个生成表达式的函数cbiaodashi()和约分函数yuefen(),而这两个函数都在product_exp中进行的,所以占用时间多。
下图为代码覆盖率测试的结果,结果表明覆盖率为93%,原因是有一些判断意外情况的代码没有执行。
四、设计过程
设计之初,我们首先想到的问题是如何规范化所有数字以及符号,因为考虑到所有的分数有规定的格式要求,索性就将所有生成的数先写成分数,再做处理。为此我们需要一个专门的函数去处理随机生成的分子和分母,将他们以规定格式返回,这样就算是解决了数字的问题。随后我们经过测试发现函数输出出来的数字无法进行约分,因此我们又专门写了一个约分函数,以便确定运算出来的答案是最简,并写入answer.txt。设计时,我们的大体思路是统一将生成的题目放入Exercises.txt,同时将答案放入answer.txt,用户需要按照格式将答案写入Exercises.txt,写完后启用cheak函数来检查用户写入的答案,将对错情况单独写入一个新的Grade.txt中。在过程之中,我们遇到了主要问题应该是cheak函数的编写,我们两个人分别写了一个cheak函数,然后交换了思路,最后决定在谭艺的cheak函数中进行改动并采用。
五、代码说明
大体函数:
其中random函数用来产生随机数,biaodashi函数用来规范分数,yuefen函数用来对结果进行约分,product_exp函数用来产生表达式并且将表达式以及答案写入对应的txt文件中,cheak函数用来检查写入的答案,检查结果在对应的Grade.txt中。其中关键的代码应该算是cheak函数,我们将用户写入的答案放入一个数组中,并且将答案放入另一个数组,最后对比俩个数组,得到Grade.txt中的内容。在Exercises.txt中检测用户的答案对我们来说是一个比较有趣的点,我们用fgetc去检测每道题目的”=“号,以及”\n“号来确认我们数组中装的是用户写入的答案,而装正确答案的数组中我们用”:“号和”\n“号来检测。
具体代码在github中可以找到。
六、测试运行
以10以内的数字产10条式子,其中题号1、3、8、10是手动输入了正确答案,其他题目均不填。
结果符合预期。
代码之所以能保证正确,是因为经过两人长时间的调试与检查。
七、项目小结
唐崇珂:本次结对项目中,我主要负责了product_exp,biaodashi,yuefen,myitoa函数的编写。因为本道题目中biaodashi函数为基本中的基本,所以在项目开始之初,我和谭艺就曾多次交换意见,查询资料后修改biaodashi函数,才能保证其得到正确的值,以及返回正确的类型,这次合作并没有太多分歧,而是彼此交换意见,然后再思考,再改动。这次的项目对我来说是一次全新的学习模式,我学会了很多有关合作,和编写代码的经验。
谭艺:在本次结对编程中,和唐崇珂合作让我受益匪浅,唐崇珂的能力在我之上,在我打代码的时候唐同学在我身旁监督和检查我的代码,并且给出很多优化的代码方案和想法,再此之前我打代码都是以自己的角度看待问题,容易陷入一个混乱的状态,导致代码也是混乱的,但是有唐崇珂同学在旁边协助的时候感觉一切都非常简单,并且享受这种合作的乐趣。遗憾的是我的实力不够,拖慢了进度,导致程序只能生成一个运算符,并且使用参数控制式子的大小和多少也没有完成,但是这次结对项目让我收获很多。
原文:https://www.cnblogs.com/wuchengttt/p/11688647.html