You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++简易计算器无法计算5+10等表达式,求技术协助

问题描述

我是编程新手,编写了一款支持+、-、*、/运算的C++简易计算器。程序能够正常启动运行,但无法完成预期的计算任务,例如输入5+10无法得到正确结果15。我反复检查代码后仍未定位到问题,恳请各位提供技术帮助。以下是我的代码:

#ifndef H112
#define H112 020215L
#include<iostream>
#include<iomanip>
#include<fstream>
#include<sstream>
#include<cmath>
#include<cstdlib>
#include<string>
#include<list>
#include <forward_list>
#include<vector>
#include<unordered_map>
#include<algorithm>
#include <array>
#include <regex>
#include<random>
#include<stdexcept>

//------------------------------------------------------------------------------
#if __GNUC__ && __GNUC__ < 5
inline std:: ios_base& defaultfloat(std:: ios_base& b)
{
    b.setf(std:: ios_base::fmtflags(0), std:: ios_base::floatfield);
    return b;
}
#endif

//------------------------------------------------------------------------------

using Unicode = long;

//------------------------------------------------------------------------------

using namespace std;

template<class T> string to_string(const T& t)
{
    ostringstream os;
    os << t;
    return os.str();
}

struct Range_error : out_of_range {    // enhanced vector range error reporting
    int index;
    Range_error(int i) :out_of_range("Range error: "+to_string(i)), index(i) { }
};


// trivially range-checked vector (no iterator checking):
template< class T> struct Vector : public std::vector<T> {
    using size_type = typename std::vector<T>::size_type;

#ifdef _MSC_VER
    // microsoft doesn't yet support C++11 inheriting constructors
    Vector() { }
    explicit Vector(size_type n) :std::vector<T>(n) {}
    Vector(size_type n, const T& v) :std::vector<T>(n,v) {}
    template <class I>
    Vector(I first, I last) : std::vector<T>(first, last) {}
    Vector(initializer_list<T> list) : std::vector<T>(list) {}
#else
    using std::vector<T>::vector;    // inheriting constructor
#endif

    T& operator[](unsigned int i) // rather than return at(i);
    {
        if (i<0||this->size()<=i) throw Range_error(i);
        return std::vector<T>::operator[](i);
    }
    const T& operator[](unsigned int i) const
    {
        if (i<0||this->size()<=i) throw Range_error(i);
        return std::vector<T>::operator[](i);
    }
};

// disgusting macro hack to get a range checked vector:
#define vector Vector

// trivially range-checked string (no iterator checking):
struct String : std::string {
    using size_type = std::string::size_type;
//    using string::string;

    char& operator[](unsigned int i) // rather than return at(i);
    {
        if (i<0||size()<=i) throw Range_error(i);
        return std::string::operator[](i);
    }

    const char& operator[](unsigned int i) const
    {
        if (i<0||size()<=i) throw Range_error(i);
        return std::string::operator[](i);
    }
};


namespace std {

    template<> struct hash<String>
    {
        size_t operator()(const String& s) const
        {
            return hash<std::string>()(s);
        }
    };

} // of namespace std


struct Exit : runtime_error {
    Exit(): runtime_error("Exit") {}
};

// error() simply disguises throws:
inline void error(const string& s)
{
    throw runtime_error(s);
}

inline void error(const string& s, const string& s2)
{
    error(s+s2);
}

inline void error(const string& s, int i)
{
    ostringstream os;
    os << s <<": " << i;
    error(os.str());
}


template<class T> char* as_bytes(T& i)    // needed for binary I/O
{
    void* addr = &i;    // get the address of the first byte
                        // of memory used to store the object
    return static_cast<char*>(addr); // treat that memory as bytes
}


inline void keep_window_open()
{
    cin.clear();
    cout << "Please enter a character to exit\n";
    char ch;
    cin >> ch;
    return;
}

inline void keep_window_open(string s)
{
    if (s=="") return;
    cin.clear();
    cin.ignore(120,'\n');
    for (;;) {
        cout << "Please enter " << s << " to exit\n";
        string ss;
        while (cin >> ss && ss!=s)
            cout << "Please enter " << s << " to exit\n";
        return;
    }
}



// error function to be used (only) until error() is introduced in Chapter 5:
inline void simple_error(string s)    // write ``error: s and exit program
{
    cerr << "error: " << s << '\n';
    keep_window_open();        // for some Windows environments
    exit(1);
}

// make std::min() and std::max() accessible on systems with antisocial macros:
#undef min
#undef max


// run-time checked narrowing cast (type conversion). See ???.
template<class R, class A> R narrow_cast(const A& a)
{
    R r = R(a);
    if (A(r)!=a) error(string("info loss"));
    return r;
}

// random number generators. See 24.7.

default_random_engine& get_rand()
{
    static default_random_engine ran;
    return ran;
};

void seed_randint(int s) { get_rand().seed(s); }

inline int randint(int min, int max) {  return uniform_int_distribution<> {min, max}(get_rand()); }

inline int randint(int max) { return randint(0, max); }

//inline double sqrt(int x) { return sqrt(double(x)); }    // to match C++0x

// container algorithms. See 21.9.

template<typename C>
using Value_type = typename C::value_type;

template<typename C>
using Iterator = typename C::iterator;

template<typename C>
    // requires Container<C>()
void sort(C& c)
{
    std::sort(c.begin(), c.end());
}

template<typename C, typename Pred>
// requires Container<C>() && Binary_Predicate<Value_type<C>>()
void sort(C& c, Pred p)
{
    std::sort(c.begin(), c.end(), p);
}

template<typename C, typename Val>
    // requires Container<C>() && Equality_comparable<C,Val>()
Iterator<C> find(C& c, Val v)
{
    return std::find(c.begin(), c.end(), v);
}

template<typename C, typename Pred>
// requires Container<C>() && Predicate<Pred,Value_type<C>>()
Iterator<C> find_if(C& c, Pred p)
{
    return std::find_if(c.begin(), c.end(), p);
}

#endif //H112

int main()
{
    cout<< "please enter expression(+,-,*,/):";
    
    int lval=0;
    int rval;
    char op;
    cin>> lval;
    if (!cin) error ("no first operand");
    while (cin>>op)
    {
        cin>>rval;
        if(!cin) error("no 2nd operand");
        switch (op){
            case '+':
                lval += rval;
                break;
            case '-':
                lval-=rval;
                break;
            case '*':
                lval*= rval;
                break;
            case '/':
                lval/=rval;
                break;
            default:
                cout<<"result:"<<lval<<'\n';
                keep_window_open();
                return 0;
        }
    }
    error("bad expression");
}

问题分析与解决

你的计算器逻辑存在一个关键问题:程序只有在遇到非+、-、*、/的字符时才会输出结果,但当你输入5+10并按下回车后,输入流中没有额外的终止字符,循环会在处理完+10后尝试继续读取下一个操作符,此时cin>>op会失败(因为输入已经结束),程序会直接走到error("bad expression"),导致无法输出计算结果。

修复方案

有两种简单的修复方式:

方式一:添加终止符(推荐)

修改程序提示,让用户输入表达式后加上一个终止符(比如=),同时在switch中添加对应分支:

int main()
{
    cout<< "please enter expression(+,-,*,/) followed by '=' to get result:";
    
    int lval=0;
    int rval;
    char op;
    cin>> lval;
    if (!cin) error ("no first operand");
    while (cin>>op)
    {
        if (op == '=') { // 匹配终止符,输出结果
            cout<<"result:"<<lval<<'\n';
            keep_window_open();
            return 0;
        }
        cin>>rval;
        if(!cin) error("no 2nd operand");
        switch (op){
            case '+':
                lval += rval;
                break;
            case '-':
                lval-=rval;
                break;
            case '*':
                lval*= rval;
                break;
            case '/':
                lval/=rval;
                break;
            default:
                error("invalid operator");
        }
    }
    error("bad expression");
}

此时用户输入5+10=就能得到正确的15。

方式二:处理输入结束的情况

如果不想用终止符,可以在循环退出后判断是否已经进行过有效计算,然后输出结果:

int main()
{
    cout<< "please enter expression(+,-,*,/):";
    
    int lval=0;
    int rval;
    char op;
    bool has_calculated = false;
    cin>> lval;
    if (!cin) error ("no first operand");
    while (cin>>op)
    {
        has_calculated = true;
        cin>>rval;
        if(!cin) error("no 2nd operand");
        switch (op){
            case '+':
                lval += rval;
                break;
            case '-':
                lval-=rval;
                break;
            case '*':
                lval*= rval;
                break;
            case '/':
                lval/=rval;
                break;
            default:
                cout<<"result:"<<lval<<'\n';
                keep_window_open();
                return 0;
        }
    }
    if (has_calculated) { // 如果进行过计算,输出结果
        cout<<"result:"<<lval<<'\n';
        keep_window_open();
        return 0;
    }
    error("bad expression");
}

这样用户输入5+10并回车后,程序会输出结果15,而不是报错。

另外注意,你的代码中包含了大量和计算器功能无关的工具类(比如Vector、String、随机数生成等),可以考虑删除这些无关代码,让程序更简洁。


内容的提问来源于stack exchange,提问作者Kim Minji

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 04:15:29