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

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

一、知如何调用

调用之法甚易,先添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。比如,此题中,应先输入路径(假设为e\calculator.exe),再输入表达式(假设为6+3-7*8),即,argv[0]="e\calculator.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;
    }


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



posted @ 2016-04-13 19:39  JackinHu  阅读(2007)  评论(10编辑  收藏  举报