天天看點

關于未成品的問題:字元類型和其他種種

0.2版本的随機出題器,問題還有,等着下次解決。先把作業交了再說。

完全重做了,基于VC(偷懶是以使用了MFC的CString類),但是也導緻了字元類型的問題。

首先是大概:出題和答案分成了兩個類,主函數用來控制參數和計算分數等。

1.答案部分(一個算數電腦)

該電腦支援+-*/^五種運算符,也支援括号(包括多重)

1 double EvaluateExpression(char* MyExpression)
 2     {
 3         //表達式求值的算符優先算法。 
 4         //設OPTR和OPND分别為運算符棧和運算數棧,OP為運算符集合。 
 5         SS *OPTR = NULL; // 運算符棧,字元元素 
 6         SN *OPND = NULL; // 運算數棧,實數元素 
 7         char TempData[20];
 8         double Data, a, b;
 9         char theta, *c, Dr[] = { '#', '\0' };
10         OPTR = Push(OPTR, '#');
11         c = strcat(MyExpression, Dr); //字元串連接配接函數,結尾處加個#,傳回連接配接後的指針
12         strcpy(TempData, "\0");//字元串拷貝函數,TempData置空 
13         while (*c != '#' || OPTR->c != '#')
14         {
15             if (!In(*c, OPSET)) //判斷是否為運算符
16             { //若不是
17                 if (*c != '.')//小數允許
18                     if (*c>'9' || *c<'0')//不是數字則出錯了
19                     {
20                         printf("input error\n");
21                         return 0;
22                     }
23                 Dr[0] = *c;
24                 strcat(TempData, Dr);//字元串連接配接函數,把算式的目前字元接在 TempData上
25                 c++; //指針指向算式的下一個字元
26                 if (In(*c, OPSET)) //若字元為運算符
27                 {
28                     Data = atof(TempData);//字元串轉換函數,轉為浮點數
29                     OPND = Push(OPND, Data); //數值入棧
30                     strcpy(TempData, "\0"); //TempData置空
31                 }
32             }
33             else
34             { // 是運算符則進棧 
35                 switch (precede(OPTR->c, *c))//對比棧頂字元和目前字元的優先度 
36                 {
37                 case '<': // 棧頂元素優先權低,則符号入棧
38                     OPTR = Push(OPTR, *c);
39                     c++;
40                     break;
41                 case '=': // 脫括号并接收下一字元 
42                     OPTR = Pop(OPTR);
43                     c++;
44                     break;
45                 case '>': // 退棧并将運算結果入棧 
46                     theta = OPTR->c;//記錄目前符号棧棧頂,即要用的運算符
47                     OPTR = Pop(OPTR); //符号棧頂出棧
48                     b = OPND->f;//記錄數值棧棧頂,作為第一個運算值
49                     OPND = Pop(OPND); //數值棧頂出棧
50                     a = OPND->f;//記錄數值棧棧頂,作為第二個運算值
51                     OPND = Pop(OPND); //數值棧頂出棧
52                     OPND = Push(OPND, Operate(a, theta, b)); //把計算結果入棧到數值棧
53                     break;
54                 } // switch 
55             }
56         } // while 
57         return OPND->f;
58     }//EvaluateExpression      

主要代碼如上,思路如注釋所示,逐字元确定是數字還是運算符,遇到運算符後入棧的數字用atof轉為數字并入數值棧,然後運算符進棧,并和棧内運算符對比優先度,若優先級高,則符号入棧,若低則與數值棧的棧頂前兩個出棧作運算值,運算符為符号棧棧頂;

入棧出棧部分省略,算符有限度的确定通過查表方式确定表如下:

1 char list[8][8] =
 2         { // 算符間的優先關系表
 3             //     '+' '-' '*' '/' '(' ')' '#' '^' 
 4             /*'+'*/'>', '>', '<', '<', '<', '>', '>', '<',
 5             /*'-'*/'>', '>', '<', '<', '<', '>', '>', '<',
 6             /*'*'*/'>', '>', '>', '>', '<', '>', '>', '<',
 7             /*'/'*/'>', '>', '>', '>', '<', '>', '>', '<',
 8             /*'('*/'<', '<', '<', '<', '<', '=', ' ', '<',
 9             /*')'*/'>', '>', '>', '>', ' ', '>', '>', '>',
10             /*'#'*/'<', '<', '<', '<', '<', ' ', '=', '<',
11             /*'^'*/'>', '>', '>', '>', '<', '>', '>', '>'
12         };
13         char oplist[8] = { '+', '-', '*', '/', '(', ')', '#', '^' };//合法運算符表      
int ReturnOpOrd(char op, char* TestOp)//查表
    {
        for (int i = 0; i < 8; i++)
            if (op == TestOp[i])
                return i;
    }
    char precede(char Aop, char Bop)//字元優先度對比
    {
        int m, n;
        m = ReturnOpOrd(Aop, OPSET);
        n = ReturnOpOrd(Bop, OPSET);
        return Prior[m][n];
    }      

經測試沒什麼大問題。能正常運作。

于是開始寫随機出題器。先随機出數字,然後随機符号,利用CString的一些特性可以很友善的增補字元串,最後得出算式的表達式:

1     void EqaSet(int Yuan, int numlv, bool symlv, bool neg = false, bool dec = false, int declv = 3, bool po = false, bool rem = false)//從左至右:元數,範圍,運算,餘數,負數,小數,小數等級,次方運算
 2     {
 3         int num[10];
 4         wchar_t *sub;
 5         srand(time(NULL));
 6         double fnum[10];
 7         char SYM;
 8         CString temp;
 9         if (dec == false)//無小數
10         {
11             for (int i = 0; i < Yuan; i++)
12                 num[i] = randnum(numlv, neg);
13         }
14         else//有小數
15         {
16             for (int i = 0; i < Yuan; i++)
17                 fnum[i] = frandnum(numlv, neg, declv);
18         }
19         //顯示的和實際計算的有差別(負數問題)
20         if (dec == false)
21             temp.Format(_T("%d"), num[0]);
22         else
23             temp.Format(_T("%g"), fnum[0]);
24         eqa = temp;
25         if (dec == false)
26         {
27             if (num[0] < 0)
28                 temp.Format(_T("(0%g)"), num[0]);
29         }
30         else
31         {
32             if (fnum[0] < 0)
33                 temp.Format(_T("(0%g)"), fnum[0]);
34         }
35         EQA = temp;
36         //end
37         for (int i = 0; i < Yuan - 1; i++)
38         {
39             SYM = randsym(symlv, po);
40             if (SYM == '/')
41                 if (num[i + 1] == 0)
42                     num[i + 1] = 2;
43             temp = SYM;
44             eqa += temp;
45             EQA += temp;
46             if (dec == false)
47                 temp.Format(_T("%d"), num[i + 1]);
48             else
49                 temp.Format(_T("%g"), fnum[i + 1]);
50             eqa += temp;
51             if (dec == false)
52             {
53                 if (num[i + 1] < 0)
54                     temp.Format(_T("(0%g)"), num[i + 1]);
55             }
56             else
57             {
58                 if (fnum[i + 1] < 0)
59                     temp.Format(_T("(0%g)"), fnum[i + 1]);
60             }
61             EQA += temp;
62         }//for
63         sub = eqa.GetBuffer(eqa.GetLength());
64         wcout << sub << "=";
65     }      

其中餘數狀态下還未實作,經測試,得出的算式正常,但是問題來了

上面得到的算式是uni編碼,即得到的字元串為wchar_t類型,我的電腦卻是識别char類型的字元串識别的。

然後去查找資料,暫時解決方法是用wcstombs_s函數來吧wchar_t字元串轉為char類型。

void EQAtoSUB()
    {
        wchar_t *sub;
        sub = EQA.GetBuffer(EQA.GetLength());
        size_t len = wcslen(sub) + 1;
        size_t converted = 0;
        SUB = (char*)malloc(len*sizeof(char));
        wcstombs_s(&converted, SUB, len, sub, _TRUNCATE);
    }      

姑且算是解決了,其實想修改電腦部分的,但是要到交作業的時候了,先用這種轉換的方式實作一下。

整合兩者後,發現問題了,小數運算的答案和使用者輸入的答案并不一緻(浮點數的精度問題),用==的方式不可能确定答對與否。

想了想,其實解決也很簡單,隻要二者之差的絕對值不超過規定的小數位數精度即可。

測試,OK,但是分數計算、帶餘數的除法計算等問題還有待解決。

0.2版本的随機電腦就是這樣了。

第一周 第二周 第三周 第四周 第五周 第六周
時間 未計
代碼量 100 500
部落格量 1
了解的知識點 git 字元類型