• 关于未成品的问题:字符类型和其他种种


    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[] = { '#', '' };
    10         OPTR = Push(OPTR, '#');
    11         c = strcat(MyExpression, Dr); //字符串连接函数,结尾处加个#,返回连接后的指针
    12         strcpy(TempData, "");//字符串拷贝函数,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
    ");
    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, ""); //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 1        
    了解的知识点 git 字符类型        
  • 相关阅读:
    【Netty之旅四】你一定看得懂的Netty客户端启动源码分析!
    Netty之旅三:Netty服务端启动源码分析,一梭子带走!
    【原创】经验分享:一个Content-Length引发的血案(almost....)
    Netty之旅二:口口相传的高性能Netty到底是什么?
    Java解压和压缩带密码的zip文件过程详解
    SQLServer安装教程(史上最详细版本)
    26.Vue技术栈开发实战-项目部署
    25.Vue技术栈开发实战-多Tab页开发
    6-6 创建产品卡片组件(1)
    6-5 创建垂直网格组件
  • 原文地址:https://www.cnblogs.com/xxjkdtx/p/5276505.html
Copyright © 2020-2023  润新知