P1957 口算练习题
这是一个经典的字符串处理与模拟题。这道题的核心考点在于非定长输入的处理(即如何判断当前行是给了运算符还是直接给的数字)。
解题思路
-
输入判断:
由于每一行的输入格式不固定(可能是
运算符 数 数,也可能是数 数),我们不能直接用cin >> char >> int >> int。- 策略:每次循环先读取第一个“标记”(Token)作为字符串。
- 检查:判断这个字符串的首字符是否为字母(
a,b,c)。- 如果是字母:更新当前的运算符,再读取后面两个整数。
- 如果是数字:将该字符串转换为第一个整数(使用
stoi或atoi),沿用上一次的运算符,再读取第二个整数。
-
计算与输出:
- 根据运算符进行加减乘计算。
- 长度获取:最简便的方法是利用
sprintf将完整的算式(如5+8=13)打印到一个字符数组中,然后直接获取该数组的长度(strlen)或转换为string求.length()。
参考代码
#include <iostream>
#include <string>
#include <cstdio> // 用于 sprintf
#include <cstring> // 用于 strlen
#include <cctype> // 用于 isalpha
using namespace std;
int main() {
int n;
cin >> n;
char op; // 用于记录当前的运算符
string first_token; // 用于读取每行的第一个数据(可能是运算符,也可能是数字)
for (int i = 0; i < n; i++) {
cin >> first_token;
int x, y;
// 判断第一个数据是字母还是数字
if (isalpha(first_token[0])) {
op = first_token[0]; // 更新运算符
cin >> x >> y; // 继续读入两个数字
} else {
// 如果不是字母,说明是数字,转换类型
x = stoi(first_token); // 将字符串转为整数
cin >> y; // 只需要再读一个数字,运算符沿用上一次的 op
}
int res = 0;
char op_symbol;
// 根据 op 执行计算
if (op == 'a') {
res = x + y;
op_symbol = '+';
} else if (op == 'b') {
res = x - y;
op_symbol = '-';
} else if (op == 'c') {
res = x * y;
op_symbol = '*';
}
// 格式化输出并计算长度
// 使用 sprintf 将结果打印到 buffer 中,方便计算总长度
char buffer[100];
sprintf(buffer, "%d%c%d=%d", x, op_symbol, y, res);
cout << buffer << endl;
cout << strlen(buffer) << endl;
}
return 0;
}
关键点解析
isalpha()的使用:这是判断字符是否为字母的标准库函数。对于初学者,也可以直接判断if (first_token[0] >= 'a' && first_token[0] <= 'z')。- 状态保持:题目中提到“若该行为两个数据,则表示本题的运算类型与上一题相同”。这就要求我们将
op变量定义在循环外部,或者保证在未读取新运算符时,op的值不被清空。 - 算式长度计算:
- 推荐做法:如代码所示,使用
sprintf生成完整字符串。这是处理“由数字和符号组成的混合字符串长度”最不易出错的方法。 - 数学做法:分别计算
x,y,res的位数,再加上符号位的数量。这种方法需要处理负数符号(例如减法结果为负数时),逻辑较繁琐,容易遗漏细节。
- 推荐做法:如代码所示,使用

浙公网安备 33010602011771号