• 计算器第四次作业——实现


    自独善上次作业后,余继而观此作业,无力不从心之感,虽有坎坷,究竟有方可循,有法可依,并不似上次那般,毫无头绪,乱来一气,此乃进步也,心中百般惊喜,自不再话下。几经修改,终是成功,虽难登大雅之堂,亦有可圈可点之处。欲知代码为何,轻触此处
    以余之愚见,此次作业,重点如下:知如何调用,明有无参数,能及时报错,懂数符转换,辨负号减号,晓孰先孰后,会处理括号。其中,又以后三者为难点。具体为何,且听余细细道来。

    一、知如何调用

    调用之法甚易,先添int argc, char* argv[]int main()括号中,即为int main(int argc, char* argv[])。此题要求用命令行进行运行,故而不用输入语句。而后按window+r,则现一搜索窗口,输cmd并按确认,便可见一黑底白字窗口,输入.exe文件之路径,并输表达式,按回车即可得结果。其中,argc是命令行总的参数个数,每输入一个参数,它会自动加一。argv[]则是argc个参数的数组,其中第0个参数是目标程序的全名,即路径加可执行文件名,以后的参数命令行后面跟的是用户输入的参数。换言之,在main函数里的cin>>stringstring=argv[]替代,即stringqrgv[]传入值,而不是cin。比如,此题中,应先输入路径(假设为ecalculator.exe),再输入表达式(假设为6+3-7*8),即,argv[0]="ecalculator.exe",argv[1]="6+3-7*8",那么我们需要的就是argv[1].此外,须知没有cin语句,无法用编译器直接运行,只能通过此法。


    二、明有无参数

    依题之要求,如见参数"-a",需先输出原表达式,再输出结果。余之做法如下:判断输入的参数个数,如果是3个,说明包含"-a",并做一标记。最后,如有标记,则先输原表达式,加"="再输结果。

           if (argc == 3)                        
    	{
    		k = 1;                            //标记是否有参数-a
    		string = argv[2];                //由命令行传入string的值
    	}
    	
    	if (argc == 2)
    		string=argv[1];
            ......
            if (k == 1)                          //有参数“-a”,输出原表达式
    	        print.printstring(q);
    
    	    cout << output << endl;             //输出结果
    

    示例:


    三、能及时报错

    报错应分为三类:其一,计算过程中数字长度超过10位;其二,除数为零;其三,括号不匹配。具体如下:

    其一

        int length_check(double number)                    //检查计算过程中数字是不是超出范围
        {
            int n;
            string string;
            stringstream stream;
    
            stream.clear();                               //
            stream << number;                             //数字转字符串
            stream >> string;                             //
            n = string.size();
    
            if (n > 10)
    	        return 0;
            else
    	        return 1;
    
        }
        ......
        
        if (length_check(t) == 0)                         //数字长度的判断
    	{
    		cout << "ERROR:digital length is beyong clculation!";
    		break;
    	}
    

    其二

        if (g == "/"&&f == 0)                           //g为运算符号,f为除数
        {
            cout << "ERROR:divisor can't be zero!" << endl;
            break;
        }
    

    其三

    扫描整个表达式,遇"(",则将其压入栈,遇")",则删栈顶元素,最后如栈为空,则正确匹配。

            int parentheses_check(string str)                  //判断括号是否匹配
            {
    	        stack<string>s;
    	        int i, length;
    	        length = str.size();
    
    	        for (i = 0; i < length; i++)
    	        {
    		        if (str[i] == '(')
    			        s.push("(");
    
    		        if (str[i] == ')')
    		        {
    			        if (!s.empty() && s.top() == "(")
    				        s.pop();
    
    			        else
    			        {
    				        return 0;
    				        break;
    			        }
    		        }
    	        }
    
    	        if (s.empty())
    		        return 1;
    	        else
    		        return 0;
            }
            ......
    
                if (parentheses_check(string) == 0)
    		        cout << "ERROR:parentheses are not matched!" << endl;
        }
    

    四、懂数符转换

    数字转与字符串之间互相转换,可添加#include<sstream>stringstream实现。注意,如多次转换,需对stream进行清除。

    如对double astring b

    数字转字符串

            #include<sstream>
            ......
            stream.clear();
    	stream << a;
    	stream >> b;
    

    字符串转数字

            #include<sstream>
            ......
            stream.clear();
    	stream << b;
    	stream >> a;
    

    五、辨负号减号

    显然,在一正确表达式中,“-”为负号只有两种情况,一是位于首位,二是处于“(”之后。在此题中,扫描时直接把负号归为数字的一部分,一同存进队列。而减号则作为运算符直接入队,这样就把负号和减号分开了。

        for (i = 0; i < input.size(); i++)
            {
    
    	        if ((input[i] >= '0' && input[i] <= '9')             //对数字和“-”的处理
    		        || input[i] == '.' || input[i] == '-')
    	        {
    		        if (input[i] == '-')
    		        {
    			        if ((i - 1 >= 0 && input[i - 1] == '(')     //负号的判断
    				        || (i == 0))
    
    				        temp = "-";
    
    			        else
    			        {
    				        queue.push(temp);
    				        temp.clear();
    				        queue.push("-");
    			        }
    		        }
    
    		        else
    			        temp += input[i];
    	        }
    
    	        else
    	        {
    		        if (!temp.empty())
    			        queue.push(temp);
    		        temp.clear();
    
    		        temp = input[i];
    
    		        if (!temp.empty())
    			        queue.push(temp);
    		        temp.clear();
    	        }
            }
    
            if (!temp.empty())
    	        queue.push(temp);
    
            return queue;
        }
    

    六、晓孰先孰后

    计算,先后顺序尤为重要,故必先设法定顺序,方可正确计算。此处暂且不论括号,余先以数字规定运算符之大小,

            int priority(string c)                              //判断优先级
            {                                                   //此处只对针加、减、乘、除
    	        if (c == "+" || c == "-")                       //四种运算,括号下面另外处理
    		        return 0;
    	        if (c == "*" || c == "/")
    		        return 1;
            }
    

    并借用2栈之进出,进行计算。二栈为何?一曰数栈,专存数字,一曰符栈,用以放运算符。访队列首元并删之,如为运算符,压入符栈,如为数字字符串,转为数字(上以具述)后,压入数栈。压入符栈前,需先比其与栈顶元素之大小。唯符栈为空或其值大于栈顶元素,方可将其压入;如若不然,取数栈顶两元素,先行计算,得其值而压入数栈。计算以一函数为之,

            double calculate1(double a, string c, double b)        //用于计算的函数
            {
    	        if (c == "+")
    	        	return (a + b);
    	        if (c == "-")
    		        return (a - b);
    	        if (c == "*")
    		        return (a*b);
    	        if (c == "/")
    		        return (a / b);
            }
    

    如此反复,直至队列为空。切记,访问队列元素之后,要将其删除,否则或是无法输出,或是结果出错,贻害无穷,余深受其害,特告知诸君。此处不贴代码,下面一起贴出。

    七、会处理括号

    括号,运算之君王也,万事以其为先。然此子狡诈异常,余甚为头疼,只得以乡村土法治之。遇括号,则取其中元素于另一栈中,再进行计算。如此叙述较为抽象,以下将连上面代码一起给出,内容略长,望诸君耐心详读,其中良莠,诸君自判,如有妙法,请传授于余,余感激不尽。

        while (!que.empty())                             //队列不为空则进入
            {
    	        if (que.front() == "(")                      //对括号内的部分进行处理(开始)
    	        {                                            //遇到左括号,压入
    		        s_str.push("(");
    		        que.pop();
    	        }
    
    	        else if (que.front() == ")")                //遇到右括号
    	        {
    		        que.pop();
    
    		        while (s_str.top() != "(")            //把字符栈里的符号弹出,压入一个队列
    		        {
    			        q_temp.push(s_str.top());
    			        s_str.pop();
    		        }
    
    		        s_str.pop();
    
    		        while (!q_temp.empty())                               //进行计算
    		        {
    			        f = s_num.top();
    			        s_num.pop();
    			        e = s_num.top();
    			        s_num.pop();
    			        g = q_temp.front();
    			        q_temp.pop();
    
    			        if (g == "/"&&f == 0)                              //除数是否为零的判断
    			        {
    				        cout << "ERROR:divisor can't be zero!" << endl;
    				        break;
    			        }
    
    			        t = calculate1(e, g, f);                          //进行计算
    
    			        if (length_check(t) == 0)                         //数字长度的判断
    			        {
    				        cout << "ERROR:digital length is beyong clculation!";
    				        break;
    			        }
    
    			        s_num.push(t);                                 //把结果压入数字栈
    		        }
    	        }                                                   //(结束)          
    
    	        else if (que.front() == "+" || que.front() == "-"   //对括号外部分的计算
    		        || que.front() == "*" || que.front() == "/")
    	        {
    		        if (s_str.empty() || s_str.top() == "(")
    		        {
    			        s_str.push(que.front());
    			        que.pop();
    		        }
    
    		        else
    		        {
    			        if (priority(que.front()) > priority(s_str.top()))
    			        {
    				        s_str.push(que.front());
    				        que.pop();
    			        }
    
    			        else
    			        {
    				        g = s_str.top();
    				        s_str.pop();
    				        f = s_num.top();
    				        s_num.pop();
    				        e = s_num.top();
    				        s_num.pop();
    
    				        if (g == "/"&&f == 0)
    				        {
    					        cout << "ERROR:divisor can't be zero!" << endl;
    					        break;
    				        }
    
    				        t = calculate1(e, g, f);
    
    				        if (length_check(t) == 0)
    				        {
    					        cout << "ERROR:digital length is beyong clculation!";
    					        break;
    				        }
    
    				        s_num.push(t);
    			        }
    		        }
    	        }
    
    	        else
    	        {
    		        stream.clear();
    		        stream << que.front();
    		        stream >> change;
    		        s_num.push(change);
    		        que.pop();
    	        }
            }
    
            while (!s_str.empty())
            {
    	        f = s_num.top();
    	        s_num.pop();
    	        e = s_num.top();
    	        s_num.pop();
    	        g = s_str.top();
    	        s_str.pop();
    
    	        if (g == "/"&&f == 0)
    	        {
    		        cout << "ERROR:divisor can't be zero!" << endl;
    		        break;
    	        }
    
    	        t = calculate1(e, g, f);
    
    	        if (length_check(t) == 0)
    	        {
    		        cout << "ERROR:digital length is beyong clculation!";
    		        break;
    	        }
    
    	        s_num.push(t);
            }
    
            final_result = s_num.top();
    
            return final_result;
        }
    


    以上内容和代码为本菜鸟之愚知拙见,如有不当和错误之处,纯属正常,望诸君开慧眼识不足,并启金口传于余,余定当感激不尽。



  • 相关阅读:
    网页日历显示控件calendar3.1
    切换“使用被动式FTP”
    href="javascript:xxx(this);"和onclick="javascript:xxx(this);"的区别
    CSS布局--上中下布局(上下固定,中间自适应)
    css字体颜色动画
    怎么让jQuery支持swipe事件
    html 5 canvas
    javascript面向对象
    WEB相关存储方式
    angularjs
  • 原文地址:https://www.cnblogs.com/jiuweilinghu/p/5388346.html
Copyright © 2020-2023  润新知