計算器第四次作業——實現


自獨善上次作業后,余繼而觀此作業,無力不從心之感,雖有坎坷,究竟有方可循,有法可依,並不似上次那般,毫無頭緒,亂來一氣,此乃進步也,心中百般驚喜,自不再話下。幾經修改,終是成功,雖難登大雅之堂,亦有可圈可點之處。欲知代碼為何,輕觸此處
以余之愚見,此次作業,重點如下:知如何調用,明有無參數,能及時報錯,懂數符轉換,辨負號減號,曉孰先孰后,會處理括號。其中,又以后三者為難點。具體為何,且聽余細細道來。

一、知如何調用

調用之法甚易,先添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;
    }


以上內容和代碼為本菜鳥之愚知拙見,如有不當和錯誤之處,純屬正常,望諸君開慧眼識不足,並啟金口傳於余,余定當感激不盡。




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM