首页 > 后端开发 > C++ > 正文

如何用C++实现一个简单的计算器 控制台输入输出和基本运算处理

P粉602998670
发布: 2025-08-13 10:29:01
原创
361人浏览过

该计算器程序使用中缀表达式转后缀表达式的策略,并通过栈实现计算;其核心步骤为:1.定义运算符优先级函数precedence;2.实现中缀转后缀函数infixtopostfix,利用栈处理运算符并生成后缀队列;3.实现后缀表达式求值函数evaluatepostfix,用栈存储操作数并根据运算符执行计算;4.主函数main接收输入并调用上述函数,同时捕获和处理异常;5.空格处理依赖stringstream自动忽略并分割token;6.扩展新运算符需在precedence添加优先级并在evaluatepostfix的switch中添加逻辑;7.支持函数调用需增加函数注册表、修改infixtopostfix识别函数名、并在evaluatepostfix中调用对应函数。

如何用C++实现一个简单的计算器 控制台输入输出和基本运算处理

用C++实现一个简单的计算器,核心在于解析用户输入的字符串,识别数字和运算符,然后按照运算优先级进行计算。 这听起来简单,但细节很多,比如错误处理、不同数据类型的兼容性等等。

如何用C++实现一个简单的计算器 控制台输入输出和基本运算处理

解决方案

如何用C++实现一个简单的计算器 控制台输入输出和基本运算处理

首先,我们需要一个主函数来接收用户的输入,并调用相应的函数进行处理。

立即学习C++免费学习笔记(深入)”;

#include <iostream>
#include <string>
#include <stack>
#include <queue>
#include <sstream>
#include <cctype>
#include <stdexcept>
#include <cmath>

using namespace std;

// 定义运算符优先级
int precedence(char op) {
    if (op == '+' || op == '-')
        return 1;
    if (op == '*' || op == '/')
        return 2;
    if (op == '^') // 指数运算
        return 3;
    return 0;
}

// 中缀表达式转后缀表达式
queue<string> infixToPostfix(const string& expression) {
    queue<string> postfixQueue;
    stack<char> operatorStack;
    stringstream ss(expression);
    string token;

    while (ss >> token) {
        if (isdigit(token[0]) || (token.size() > 1 && isdigit(token[1]) && (token[0] == '-' || token[0] == '+'))) {
            // 数字直接入队列 (处理负数)
            postfixQueue.push(token);
        } else if (token == "(") {
            operatorStack.push('(');
        } else if (token == ")") {
            while (!operatorStack.empty() && operatorStack.top() != '(') {
                postfixQueue.push(string(1, operatorStack.top()));
                operatorStack.pop();
            }
            if (!operatorStack.empty() && operatorStack.top() == '(') {
                operatorStack.pop(); // 弹出 '('
            } else {
                throw invalid_argument("Mismatched parentheses"); // 括号不匹配
            }
        } else {
            // 运算符处理
            char op = token[0]; // 假设token长度为1
            while (!operatorStack.empty() && precedence(op) <= precedence(operatorStack.top())) {
                postfixQueue.push(string(1, operatorStack.top()));
                operatorStack.pop();
            }
            operatorStack.push(op);
        }
    }

    // 将剩余运算符弹出
    while (!operatorStack.empty()) {
        if (operatorStack.top() == '(') {
            throw invalid_argument("Mismatched parentheses"); // 括号不匹配
        }
        postfixQueue.push(string(1, operatorStack.top()));
        operatorStack.pop();
    }

    return postfixQueue;
}

// 计算后缀表达式
double evaluatePostfix(queue<string> postfixQueue) {
    stack<double> operandStack;

    while (!postfixQueue.empty()) {
        string token = postfixQueue.front();
        postfixQueue.pop();

        if (isdigit(token[0]) || (token.size() > 1 && isdigit(token[1]) && (token[0] == '-' || token[0] == '+'))) {
            // 数字入栈
            operandStack.push(stod(token));
        } else {
            // 运算符处理
            if (operandStack.size() < 2) {
                throw invalid_argument("Invalid expression"); // 缺少操作数
            }
            double operand2 = operandStack.top();
            operandStack.pop();
            double operand1 = operandStack.top();
            operandStack.pop();
            char op = token[0];

            switch (op) {
                case '+': operandStack.push(operand1 + operand2); break;
                case '-': operandStack.push(operand1 - operand2); break;
                case '*': operandStack.push(operand1 * operand2); break;
                case '/':
                    if (operand2 == 0) {
                        throw invalid_argument("Division by zero"); // 除数为零
                    }
                    operandStack.push(operand1 / operand2);
                    break;
                case '^': operandStack.push(pow(operand1, operand2)); break;
                default: throw invalid_argument("Invalid operator"); // 无效运算符
            }
        }
    }

    if (operandStack.size() != 1) {
        throw invalid_argument("Invalid expression"); // 表达式无效
    }

    return operandStack.top();
}

int main() {
    string expression;
    cout << "请输入算术表达式(用空格分隔数字和运算符,支持+ - * / ^):" << endl;
    getline(cin, expression);

    try {
        queue<string> postfixQueue = infixToPostfix(expression);
        double result = evaluatePostfix(postfixQueue);
        cout << "结果: " << result << endl;
    } catch (const exception& e) {
        cerr << "错误: " << e.what() << endl;
        return 1;
    }

    return 0;
}
登录后复制

这段代码首先定义了运算符的优先级,然后实现了一个中缀表达式转后缀表达式的函数

infixToPostfix
登录后复制
登录后复制
登录后复制
,最后实现了一个计算后缀表达式的函数
evaluatePostfix
登录后复制
登录后复制
登录后复制
登录后复制
。 主函数负责接收用户输入,调用这两个函数,并输出结果。当然,这段代码还包含了一些错误处理,比如括号不匹配、除数为零等等。

如何用C++实现一个简单的计算器 控制台输入输出和基本运算处理

如何处理用户输入中的空格?

在上面的代码中,我们使用了

stringstream
登录后复制
登录后复制
来处理用户输入。
stringstream
登录后复制
登录后复制
会自动忽略空格,并将字符串分割成一个个的 token。 因此,用户可以在输入表达式时随意添加空格,程序仍然可以正确解析。

如何扩展计算器的功能,比如添加更多运算符?

要添加更多运算符,首先需要在

precedence
登录后复制
函数中定义新运算符的优先级。 然后,在
evaluatePostfix
登录后复制
登录后复制
登录后复制
登录后复制
函数的
switch
登录后复制
语句中添加新运算符的处理逻辑。 例如,要添加求模运算符
%
登录后复制
,可以这样修改代码:

// 在 precedence 函数中添加 % 的优先级
int precedence(char op) {
    if (op == '+' || op == '-')
        return 1;
    if (op == '*' || op == '/')
        return 2;
    if (op == '%') // 求模运算
        return 2;
    if (op == '^') // 指数运算
        return 3;
    return 0;
}

// 在 evaluatePostfix 函数的 switch 语句中添加 % 的处理逻辑
switch (op) {
    case '+': operandStack.push(operand1 + operand2); break;
    case '-': operandStack.push(operand1 - operand2); break;
    case '*': operandStack.push(operand1 * operand2); break;
    case '/':
        if (operand2 == 0) {
            throw invalid_argument("Division by zero"); // 除数为零
        }
        operandStack.push(operand1 / operand2);
        break;
    case '%':
        if (operand2 == 0) {
            throw invalid_argument("Division by zero"); // 除数为零
        }
        operandStack.push(fmod(operand1, operand2)); // 使用 fmod 处理浮点数求模
        break;
    case '^': operandStack.push(pow(operand1, operand2)); break;
    default: throw invalid_argument("Invalid operator"); // 无效运算符
}
登录后复制

注意,求模运算需要使用

fmod
登录后复制
函数来处理浮点数。

如何处理更复杂的表达式,比如包含函数调用?

处理包含函数调用的表达式会更复杂。 首先,需要在

infixToPostfix
登录后复制
登录后复制
登录后复制
函数中识别函数名和参数。 然后,在
evaluatePostfix
登录后复制
登录后复制
登录后复制
登录后复制
函数中调用相应的函数,并将结果压入栈中。 这需要一个函数注册表,将函数名和函数指针关联起来。 例如:

#include <map>

// 定义函数指针类型
typedef double (*FunctionPtr)(double);

// 函数注册表
map<string, FunctionPtr> functionTable;

// 注册函数
void registerFunction(const string& name, FunctionPtr function) {
    functionTable[name] = function;
}

// 实现一个示例函数
double sine(double x) {
    return sin(x);
}

int main() {
    // 注册 sine 函数
    registerFunction("sin", sine);

    // ... (修改 infixToPostfix 和 evaluatePostfix 函数)

    return 0;
}
登录后复制

然后,需要修改

infixToPostfix
登录后复制
登录后复制
登录后复制
函数,识别函数调用,并将函数名和参数转换为后缀表达式。 例如,将
sin(3.14)
登录后复制
转换为
3.14 sin
登录后复制
。 最后,修改
evaluatePostfix
登录后复制
登录后复制
登录后复制
登录后复制
函数,当遇到函数名时,从函数注册表中查找函数指针,并调用该函数。 这部分代码比较复杂,需要仔细设计和实现。

以上就是如何用C++实现一个简单的计算器 控制台输入输出和基本运算处理的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号