结对编程-四则运算练习题
一、作业要求
小学老师要每周给同学出300道四则运算练习题。
这个程序有很多种实现方式:
C/C++
C#/VB.net/Java
Excel
Unix Shell
Emacs/Powershell/Vbscript
Perl
Python
两个运算符,100 以内的数字,不写答案。
需要检查答案是否正确,并且保证答案在 0..1000 之间
二、结对编程成员:2352308(本博客)、2352106
三、运行环境:CodeBlocks
四、算法设计思路
(一)第一版
(1)核心设计思路:
题目生成:
完全随机生成两个运算符(+ - * /)和三个操作数(1-100)
对除法特殊处理:确保除数是被除数的因数(通过get_divisor())
通过is_valid_expression()验证题目有效性(结果范围、除法合法性等)
运算逻辑:
calculate()实现运算符优先级(先乘除后加减)
限制结果范围(0-1000),避免负数或过大数值
用户交互:
固定生成300题,每5题分组显示
最终输出总正确率和评价
(2)特点:
简单直接,无用户自定义选项
完全随机的运算符组合,可能生成单一运算符题目(如 a + b + c)
输入处理较基础(仅scanf)
(二)第二版
(1)改进点:
新增功能:
每5题显示分组正确率(group_correct计数器)
更清晰的题目分组标题(=== Group X-Y Summary ===)
算法优化:
计算和验证逻辑与第一个版本一致
增加中间统计功能,提升用户反馈即时性
(2)设计思路:
在基础版本上增强交互性
通过分组统计帮助用户了解阶段性学习效果
仍保持完全随机的运算符选择
(三)第三版
(1)核心改进:
运算符选择:
用户可自定义运算符集合(如仅选择+ *)
通过allowed_ops数组和op_count实现灵活控制
混合运算:
当用户选择多个运算符时,确保题目是混合运算(如 a + b * c)
当用户选择四个运算符时,系统将随机混合出题
通过random_op()从用户选择的运算符中随机挑选
增强交互:
支持随时退出(输入q)
退出时显示:完成题数、剩余题数、当前正确率
使用fgets替代scanf,输入处理更好
验证逻辑扩展:
is_valid_expression()新增运算符范围检查
确保题目仅包含用户选择的运算符
(2)设计思路:
以用户需求为中心,提供高度定制化
通过强制混合运算提升题目多样性
完善的退出机制和实时统计功能
五、程序代码
(一)第一版
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <string.h>
// 函数声明
int random_num();
char random_op();
int get_divisor(int dividend);
int calculate(int a, char op1, int b, char op2, int c);
bool is_valid_expression(int a, char op1, int b, char op2, int c);
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c);
void clear_input_buffer();
// 生成1-100的随机数
int random_num() {
return rand() % 100 + 1;
}
// 随机选择运算符
char random_op() {
char ops[] = {'+', '-', '*', '/'};
return ops[rand() % 4];
}
// 生成能整除被除数的除数
int get_divisor(int dividend) {
if (dividend == 0) return 1;
int factors[20];
int count = 0;
for (int i = 1; i <= dividend && i <= 100; i++) {
if (dividend % i == 0) {
factors[count++] = i;
}
}
return count > 0 ? factors[rand() % count] : 1;
}
// 计算表达式结果
int calculate(int a, char op1, int b, char op2, int c) {
int result;
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
if (op1 == '*') {
result = a * b;
} else {
result = b != 0 ? a / b : -1;
}
result = op2 == '+' ? result + c : result - c;
}
else if ((op2 == '*' || op2 == '/') && (op1 == '+' || op1 == '-')) {
if (op2 == '*') {
result = b * c;
} else {
result = c != 0 ? b / c : -1;
}
result = op1 == '+' ? a + result : a - result;
}
else {
if (op1 == '+') result = a + b;
else if (op1 == '-') result = a - b;
else if (op1 == '*') result = a * b;
else result = b != 0 ? a / b : -1;
if (op2 == '+') result += c;
else if (op2 == '-') result -= c;
else if (op2 == '*') result *= c;
else result = c != 0 ? result / c : -1;
}
return result;
}
// 检查表达式是否有效
bool is_valid_expression(int a, char op1, int b, char op2, int c) {
int result = calculate(a, op1, b, op2, c);
if (result < 0 || result > 1000) return false;
if (op1 == '/' && (b == 0 || a % b != 0)) return false;
if (op2 == '/' && c == 0) return false;
if (op1 == '-' && a < b) return false;
if (op2 == '-') {
int temp = (op1 == '+') ? a + b :
(op1 == '-') ? a - b :
(op1 == '*') ? a * b : a / b;
if (temp < c) return false;
}
if (op1 == '*' && a * b > 500) return false;
if (op2 == '*' && b * c > 500) return false;
return true;
}
// 生成有效的表达式
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c) {
while (true) {
*a = random_num();
*op1 = random_op();
*op2 = random_op();
if (*op1 == '/') {
*b = get_divisor(*a);
} else {
*b = random_num();
}
if (*op2 == '/') {
int temp;
if (*op1 == '+') temp = *a + *b;
else if (*op1 == '-') temp = *a - *b;
else if (*op1 == '*') temp = *a * *b;
else temp = *a / *b;
*c = get_divisor(temp);
} else {
*c = random_num();
}
if (is_valid_expression(*a, *op1, *b, *op2, *c)) {
break;
}
}
}
void clear_input_buffer() {
while (getchar() != '\n');
}
int main() {
srand(time(NULL));
int count = 0;
const int total = 300;
int correct_answers = 0;
printf("Welcome to the Math Practice Generator!\n");
printf("We will generate %d problems, 5 at a time.\n\n", total);
while (count < total) {
if (count % 5 == 0) {
printf("\n=== Problems %d-%d ===\n", count+1, (count+5 > total) ? total : count+5);
}
int a, b, c;
char op1, op2;
generate_valid_expression(&a, &op1, &b, &op2, &c);
int correct_answer = calculate(a, op1, b, op2, c);
int user_answer;
printf("%d. %d %c %d %c %d = ", count + 1, a, op1, b, op2, c);
while (scanf("%d", &user_answer) != 1) {
printf("Invalid input, please enter a number: ");
clear_input_buffer();
}
clear_input_buffer();
if (user_answer == correct_answer) {
printf("good job!\n");
correct_answers++;
} else {
printf("it's wrong! The correct answer is: %d\n", correct_answer);
}
count++;
}
printf("\n=== Practice Completed ===\n");
printf("Total problems: %d\n", total);
printf("Correct answers: %d\n", correct_answers);
printf("Accuracy: %.1f%%\n", (float)correct_answers / total * 100);
if (correct_answers == total) {
printf("Excellent! Perfect score!\n");
} else if (correct_answers >= total * 0.8) {
printf("Great job! Keep it up!\n");
} else if (correct_answers >= total * 0.6) {
printf("Not bad, keep practicing!\n");
} else {
printf("You need more practice!\n");
}
return 0;
}
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <string.h>
// 函数声明
int random_num();
char random_op();
int get_divisor(int dividend);
int calculate(int a, char op1, int b, char op2, int c);
bool is_valid_expression(int a, char op1, int b, char op2, int c);
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c);
void clear_input_buffer();
// 生成1-100的随机数
int random_num() {
return rand() % 100 + 1;
}
// 随机选择运算符
char random_op() {
char ops[] = {'+', '-', '*', '/'};
return ops[rand() % 4];
}
// 生成能整除被除数的除数
int get_divisor(int dividend) {
if (dividend == 0) return 1;
int factors[20];
int count = 0;
for (int i = 1; i <= dividend && i <= 100; i++) {
if (dividend % i == 0) {
factors[count++] = i;
}
}
return count > 0 ? factors[rand() % count] : 1;
}
// 计算表达式结果(考虑运算符优先级)
int calculate(int a, char op1, int b, char op2, int c) {
int result;
// 处理运算符优先级
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
// 先计算 op1
if (op1 == '*') {
result = a * b;
} else {
result = b != 0 ? a / b : -1;
}
// 再计算 op2
result = op2 == '+' ? result + c : result - c;
}
else if ((op2 == '*' || op2 == '/') && (op1 == '+' || op1 == '-')) {
// 先计算 op2
if (op2 == '*') {
result = b * c;
} else {
result = c != 0 ? b / c : -1;
}
// 再计算 op1
result = op1 == '+' ? a + result : a - result;
}
else {
// 无优先级冲突,从左到右计算
if (op1 == '+') result = a + b;
else if (op1 == '-') result = a - b;
else if (op1 == '*') result = a * b;
else result = b != 0 ? a / b : -1;
if (op2 == '+') result += c;
else if (op2 == '-') result -= c;
else if (op2 == '*') result *= c;
else result = c != 0 ? result / c : -1;
}
return result;
}
// 检查表达式是否有效
bool is_valid_expression(int a, char op1, int b, char op2, int c) {
// 检查计算结果范围
int result = calculate(a, op1, b, op2, c);
if (result < 0 || result > 1000) return false;
// 检查除法合法性
if (op1 == '/' && (b == 0 || a % b != 0)) return false;
if (op2 == '/' && c == 0) return false;
// 检查减法合法性
if (op1 == '-' && a < b) return false;
if (op2 == '-') {
int temp = (op1 == '+') ? a + b :
(op1 == '-') ? a - b :
(op1 == '*') ? a * b : a / b;
if (temp < c) return false;
}
// 限制乘法结果范围
if (op1 == '*' && a * b > 500) return false;
if (op2 == '*' && b * c > 500) return false;
return true;
}
// 生成有效的表达式
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c) {
while (true) {
*a = random_num();
*op1 = random_op();
*op2 = random_op();
// 处理第一个运算符是除法的情况
if (*op1 == '/') {
*b = get_divisor(*a);
} else {
*b = random_num();
}
// 处理第二个运算符是除法的情况
if (*op2 == '/') {
int temp;
if (*op1 == '+') temp = *a + *b;
else if (*op1 == '-') temp = *a - *b;
else if (*op1 == '*') temp = *a * *b;
else temp = *a / *b;
*c = get_divisor(temp);
} else {
*c = random_num();
}
// 如果表达式有效,则退出循环
if (is_valid_expression(*a, *op1, *b, *op2, *c)) {
break;
}
}
}
// 清空输入缓冲区
void clear_input_buffer() {
while (getchar() != '\n');
}
int main() {
srand(time(NULL)); // 初始化随机数种子
int count = 0;
const int total = 300;
int correct_answers = 0;
int group_correct = 0; // 每组的正确答题数
printf("Welcome to the Math Practice Generator!\n");
printf("We will generate %d problems, 5 at a time.\n\n", total);
while (count < total) {
// 每5题显示分组标题
if (count % 5 == 0) {
printf("\n=== Problems %d-%d ===\n", count+1, (count+5 > total) ? total : count+5);
}
int a, b, c;
char op1, op2;
// 生成有效表达式
generate_valid_expression(&a, &op1, &b, &op2, &c);
int correct_answer = calculate(a, op1, b, op2, c);
int user_answer;
// 显示题目并获取用户输入
printf("%d. %d %c %d %c %d = ", count + 1, a, op1, b, op2, c);
// 处理非数字输入
while (scanf("%d", &user_answer) != 1) {
printf("Invalid input, please enter a number: ");
clear_input_buffer();
}
clear_input_buffer();
// 检查答案
if (user_answer == correct_answer) {
printf("good job!\n");
correct_answers++;
group_correct++;
} else {
printf("it's wrong! The correct answer is: %d\n", correct_answer);
}
count++;
// 每5题显示一次分组统计
if (count % 5 == 0) {
printf("\n=== Group %d-%d Summary ===\n", count-4, count);
printf("Correct answers in this group: %d/5\n", group_correct);
printf("Accuracy: %.1f%%\n\n", (float)group_correct / 5 * 100);
group_correct = 0; // 重置分组计数器
}
}
// 最终统计
printf("\n=== Practice Completed ===\n");
printf("Total problems: %d\n", total);
printf("Correct answers: %d\n", correct_answers);
printf("Accuracy: %.1f%%\n", (float)correct_answers / total * 100);
// 根据正确率给出评价
if (correct_answers == total) {
printf("Excellent! Perfect score!\n");
} else if (correct_answers >= total * 0.8) {
printf("Great job! Keep it up!\n");
} else if (correct_answers >= total * 0.6) {
printf("Not bad, keep practicing!\n");
} else {
printf("You need more practice!\n");
}
return 0;
}
点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
// 函数声明
int random_num();
char random_op(char* allowed_ops, int op_count);
int get_divisor(int dividend);
int calculate(int a, char op1, int b, char op2, int c);
bool is_valid_expression(int a, char op1, int b, char op2, int c, char* allowed_ops, int op_count);
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c, char* allowed_ops, int op_count);
void clear_input_buffer();
void print_summary(int total, int completed, int correct);
// 生成1-100的随机数
int random_num() {
return rand() % 100 + 1;
}
// 从允许的运算符中随机选择
char random_op(char* allowed_ops, int op_count) {
return allowed_ops[rand() % op_count];
}
// 生成能整除被除数的除数
int get_divisor(int dividend) {
if (dividend == 0) return 1;
int factors[20];
int count = 0;
for (int i = 1; i <= dividend && i <= 100; i++) {
if (dividend % i == 0) {
factors[count++] = i;
}
}
return count > 0 ? factors[rand() % count] : 1;
}
// 计算表达式结果(考虑运算符优先级)
int calculate(int a, char op1, int b, char op2, int c) {
int result;
// 处理运算符优先级
if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) {
// 先计算 op1
if (op1 == '*') {
result = a * b;
} else {
result = b != 0 ? a / b : -1;
}
// 再计算 op2
result = op2 == '+' ? result + c : result - c;
}
else if ((op2 == '*' || op2 == '/') && (op1 == '+' || op1 == '-')) {
// 先计算 op2
if (op2 == '*') {
result = b * c;
} else {
result = c != 0 ? b / c : -1;
}
// 再计算 op1
result = op1 == '+' ? a + result : a - result;
}
else {
// 无优先级冲突,从左到右计算
if (op1 == '+') result = a + b;
else if (op1 == '-') result = a - b;
else if (op1 == '*') result = a * b;
else result = b != 0 ? a / b : -1;
if (op2 == '+') result += c;
else if (op2 == '-') result -= c;
else if (op2 == '*') result *= c;
else result = c != 0 ? result / c : -1;
}
return result;
}
// 检查表达式是否有效
bool is_valid_expression(int a, char op1, int b, char op2, int c, char* allowed_ops, int op_count) {
// 检查运算符是否在允许范围内
bool op1_valid = false, op2_valid = false;
for (int i = 0; i < op_count; i++) {
if (op1 == allowed_ops[i]) op1_valid = true;
if (op2 == allowed_ops[i]) op2_valid = true;
}
if (!op1_valid || !op2_valid) return false;
// 检查计算结果范围
int result = calculate(a, op1, b, op2, c);
if (result < 0 || result > 1000) return false;
// 检查除法合法性
if (op1 == '/' && (b == 0 || a % b != 0)) return false;
if (op2 == '/' && c == 0) return false;
// 检查减法合法性
if (op1 == '-' && a < b) return false;
if (op2 == '-') {
int temp = (op1 == '+') ? a + b :
(op1 == '-') ? a - b :
(op1 == '*') ? a * b : a / b;
if (temp < c) return false;
}
// 限制乘法结果范围
if (op1 == '*' && a * b > 500) return false;
if (op2 == '*' && b * c > 500) return false;
return true;
}
// 生成有效的表达式
void generate_valid_expression(int *a, char *op1, int *b, char *op2, int *c, char* allowed_ops, int op_count) {
while (true) {
*a = random_num();
*op1 = random_op(allowed_ops, op_count);
*op2 = random_op(allowed_ops, op_count);
if (*op1 == '/') {
*b = get_divisor(*a);
} else {
*b = random_num();
}
if (*op2 == '/') {
int temp;
if (*op1 == '+') temp = *a + *b;
else if (*op1 == '-') temp = *a - *b;
else if (*op1 == '*') temp = *a * *b;
else temp = *a / *b;
*c = get_divisor(temp);
} else {
*c = random_num();
}
if (is_valid_expression(*a, *op1, *b, *op2, *c, allowed_ops, op_count)) {
break;
}
}
}
// 清空输入缓冲区
void clear_input_buffer() {
while (getchar() != '\n');
}
// 打印退出时的统计信息
void print_summary(int total, int completed, int correct) {
printf("\n=== Practice Summary ===\n");
printf("Total problems: %d\n", total);
printf("Completed: %d\n", completed);
printf("Remaining: %d\n", total - completed);
if (completed > 0) {
printf("Correct answers: %d\n", correct);
printf("Accuracy: %.1f%%\n", (float)correct / completed * 100);
if (correct == completed) {
printf("Excellent! Perfect score!\n");
} else if (correct >= completed * 0.8) {
printf("Great job! Keep it up!\n");
} else if (correct >= completed * 0.6) {
printf("Not bad, keep practicing!\n");
} else {
printf("You need more practice!\n");
}
} else {
printf("No problems completed.\n");
}
}
int main() {
srand(time(NULL));
const int total = 300;
int count = 0;
int correct_answers = 0;
int group_correct = 0;
char allowed_ops[4];
int op_count = 0;
printf("Welcome to the Math Practice Generator!\n");
printf("Press 'q' at any time to quit and see your summary.\n");
// 运算符选择菜单
printf("\nSelect operators to include:\n");
printf("1. + (Addition)\n");
printf("2. - (Subtraction)\n");
printf("3. * (Multiplication)\n");
printf("4. / (Division)\n");
printf("Enter numbers separated by spaces (e.g. '1 2 3' for +-*): ");
char input[20];
fgets(input, sizeof(input), stdin);
char* token = strtok(input, " ");
while (token != NULL) {
int choice = atoi(token);
if (choice >= 1 && choice <= 4) {
allowed_ops[op_count++] = "+-*/"[choice-1];
}
token = strtok(NULL, " ");
}
if (op_count == 0) {
allowed_ops[0] = '+';
allowed_ops[1] = '-';
allowed_ops[2] = '*';
allowed_ops[3] = '/';
op_count = 4;
printf("No valid selection. Using all operators by default.\n");
}
printf("\nSelected operators: ");
for (int i = 0; i < op_count; i++) {
printf("%c ", allowed_ops[i]);
}
printf("\n");
printf("\nWe will generate %d problems, 5 at a time.\n", total);
printf("Enter 'q' to quit early.\n\n");
while (count < total) {
if (count % 5 == 0 && count > 0) {
printf("\n=== Group %d-%d Summary ===\n", count-4, count);
printf("Correct answers in this group: %d/5\n", group_correct);
printf("Accuracy: %.1f%%\n\n", (float)group_correct / 5 * 100);
group_correct = 0;
}
if (count % 5 == 0) {
printf("\n=== Problems %d-%d ===\n", count+1, (count+5 > total) ? total : count+5);
}
int a, b, c;
char op1, op2;
generate_valid_expression(&a, &op1, &b, &op2, &c, allowed_ops, op_count);
int correct_answer = calculate(a, op1, b, op2, c);
int user_answer;
char user_input[20];
printf("%d. %d %c %d %c %d = ", count + 1, a, op1, b, op2, c);
fgets(user_input, sizeof(user_input), stdin);
// 检查是否要退出
if (tolower(user_input[0]) == 'q') {
print_summary(total, count, correct_answers);
return 0;
}
user_answer = atoi(user_input);
if (user_answer == correct_answer) {
printf("good job!\n");
correct_answers++;
group_correct++;
} else {
printf("it's wrong! The correct answer is: %d\n", correct_answer);
}
count++;
}
// 最终统计
if (count % 5 == 0 && count > 0) {
printf("\n=== Group %d-%d Summary ===\n", count-4, count);
printf("Correct answers in this group: %d/5\n", group_correct);
printf("Accuracy: %.1f%%\n\n", (float)group_correct / 5 * 100);
}
print_summary(total, count, correct_answers);
return 0;
}
(一)第一版
计算正确显示:good job!
计算错误显示:it's wrong!The ccorrect answer is: +正确答案

完成三百题显示正确率:

(二)第二版
考虑到5题为一组,所以添加了每5题统计一次正确率,300道题全部完成后统计一次总的正确率:

(三)第三版
添加了自定义运算符集合,可自由选择题目出现的运算符:

添加了随时可结束,输入q时结束练习,并统计所完成的题目,未完成的题目,正确率等:

选择两个运算符:

选择两个以上运算符时,系统将随机组合出题:


当输入非1(+),2(-),3(*),4(/)时,系统将忽略该数字,顺延识别下一个数字:

七、版本对比分析

八、体会
2352308:最初的基础版本像一张白纸,虽然功能完整但缺乏边界。通过逐步添加限制条件(如分组统计、运算符过滤、输入校验),让代码产生了价值。例如第三个版本中混合运算的设计,表面上限制了随机性,实则通过约束条件(如while (*op1 == *op2))倒生成更符合训练目标的题目。在本次的结对编程中我体会到这不仅仅是一次分工的合作,更是双方的思维碰撞使得程序代码不断地优化。这种方式不仅帮助我们及时发现并修正潜在问题,更显著提升了代码质量。当然,过程中也遇到了一些挑战,比如代码理解上的差异导致需要花费额外时间沟通协调。但正是这些挑战促使我们不断优化沟通方式,确保双方思路保持一致。这次经历让我收获颇丰。通过密切合作,我们不仅互相学习到对方的编程优点,更发现了自身编码习惯中的不足之处。
2352106:这次结对编程实验让我更加体会到团队合作的重要性。我们的任务是实现三百道加减乘除运算,在分工合作中,我和搭档充分发挥各自的优势。在实验中,我们不断讨论,遇到问题时及时调整策略,确保程序高效准确。例如,如何高效处理大量数据。通过及时沟通,我们一起探讨了解决方案,并在调试过程中互相帮助,解决了多个问题。通过这次合作,我不仅提升了编程技巧,还意识到良好的沟通和分工能极大提高效率。结对编程让我学到了如何更好地协作,也让我更注重代码质量和可维护性。这次经历对我的编程学习非常有帮助。总体来说,这次实验让我认识到,团队合作和高效的沟通是顺利完成任务的关键,结对编程是一种提升编程能力和解决问题的有效方式。
浙公网安备 33010602011771号