编程挑战简易计算器的编制

编程挑战-简易计算器程序的编制
简易计算器功能要求:输入二个实数
及“+、-、*、/”,计算他们的结果并输出结果,同时,在屏幕上printf("设计:
210xX 谢谢使用!\n"):等字样

大概如下。

float a,b;
char  ch;
scanf("%f%f%c",&a,&b,&c);
switch (c)
{
case '+':
...
}


作者:ClockIT
链接:https://www.zhihu.com/question/504000136/answer/2259806858
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

#include <stdio.h>
#include <stdlib.h>
#include <math.h> // fmod()

inline unsigned int priority(const wchar_t c) //优先级
{
    switch (c)
    {
    case L' ': case L' ':
        return 1;

    case L'(': case L'(':
        return 2;

    case L')': case L')':
        return 3;

    case L'+': case L'-': case L'+': case L'-':
        return 4;

    case L'*': case L'/': case L'×': case L'÷': case L'*': case L'/':
        return 5;

    case L'^': case L'^':
        return 6;

    default:
        return 0;
    }
}

inline int Calculation(double* value, size_t* vc, const wchar_t opera)
{
    if (vc == 0 || *vc < 2)
        return 0;

    double VT1 = value[--(*vc)];
    double* back = &value[*vc - 1];

    switch (opera)
    {
    case L'^': case L'^':
        *back = fmod(*back, VT1);
        break;
    case L'*': case L'×': case L'*':
        *back = *back * VT1;
        break;
    case L'/': case L'÷': case L'/':
        *back = ((VT1 == 0.0) ? 0.0 : (*back / VT1));    // 不能除以0.0
        break;
    case L'+': case L'+':
        *back = *back + VT1;
        break;
    case L'-': case L'-':
        *back = *back - VT1;
        break;
    default:    // 未知运算符
        return 0;
    }
    return 1;
}

double AnalyticFormula(const wchar_t* _Expr)
{
    if (_Expr == 0)
        return 0.0;

    // 计算字符串长度(不包含最后的L'\0'长度)
    const wchar_t* EndPtr = _Expr;
    while (*EndPtr != L'\0')
        EndPtr++;

    // 如果是C++可以用std::stack()或std::vector()代替,C语言需要自己写一个
    const size_t len = EndPtr - _Expr; // _Expr字符串长度
    if (len == 0)
        return 0.0;
    double* value = (double*)malloc(sizeof(double) * len);
    if (value == 0)
        return 0.0;
    wchar_t* opera = (wchar_t*)malloc(sizeof(wchar_t) * len);
    if (opera == 0)
    {
        free(value);
        return 0.0;
    }
    size_t vc = 0;
    size_t oc = 0;

    const wchar_t* pCh = _Expr;
    unsigned int pri = priority(*pCh);

    // 针对开头第一个字符的判断优化
    switch (pri)
    {
    case 0: // 不是运算符
        if (((*pCh >= L'0') && (*pCh <= L'9')) || ((*pCh >= L'0') && (*pCh <= L'9')))
        {
            //[[fallthrough]]; // C23或C++17用于去除 C26819 警告用的注释,低于这个版本的在前面加上两个斜线注释掉就行
    case 4: // 是加减号运算符
        goto GotoValueAdd;
        }
        //[[fallthrough]];
    default: // 其他字符,比如右括号等
            goto GotoEndWhile;

    case 2: // 左括号
        opera[oc++] = *pCh;
        //[[fallthrough]];
    case 1: // 空格
        pCh++;
        break;
    }

    // 从左到右扫描中缀表达式
    do
    {
        // 是否是运算分量
        if (((*pCh >= L'0') && (*pCh <= L'9')) || ((*pCh >= L'0') && (*pCh <= L'9')))
        {
            if (vc >= len)
                break;

        GotoValueAdd:
            const wchar_t* t = pCh;
            value[vc++] = wcstod(t, (wchar_t**)&pCh);
            if (t == pCh)
                goto GotoEndWhile; // 字符转浮点数失败
        }
        else
        {
            if (oc >= len)
                break;

            pri = priority(*pCh);
            switch (pri)
            {
            case 0: // 未知字符
                goto GotoEndWhile;

            case 3: // 右括号
                do
                {
                    if (oc == 0)
                        goto GotoEndWhile; // 和左括号数量不匹配
                    if (priority(opera[oc - 1]) == 2)
                    {
                        oc--;
                        break;
                    }
                    if (!Calculation(value, &vc, opera[--oc]))
                        goto GotoEndWhile; // 计算出错,value数量不正确或opera字符错误!
                } while (1);
                //[[fallthrough]];
            case 1: // 空格跳过
                pCh++;
                break;

            default: // 运算符
                if (pri == 4) // 检查该+-符号是否表示为数字而不是运算符
                {
                    const wchar_t* prev = pCh - 1;
                    unsigned int flag;
                    while ((flag = priority(*prev)) == 1 && prev > _Expr)
                        prev--;
                    if (flag > 3)
                    {
                        if (vc >= len) // 防止内存溢出
                            goto GotoEndWhile;
                        else
                            goto GotoValueAdd;
                    }
                }
                // 空栈直接入栈,优先级比较
                do
                {
                    if (oc == 0 || pri > priority(opera[oc - 1]))
                    {
                        //[[fallthrough]];
            case 2: // 左括号
                opera[oc++] = *pCh++;
                break;
                    }
                    if (!Calculation(value, &vc, opera[--oc]))
                    {
                        goto GotoEndWhile; // 计算出错,value数量不正确或opera字符错误!
                    }
                } while (1);
                break;
            }
        }
    } while (*pCh != L'\0');

GotoEndWhile:
    while (oc != 0)
    {
        const wchar_t t = opera[oc - 1];
        if (t == L'(' || t == L')')
            oc--;
        else
            Calculation(value, &vc, opera[--oc]);
    }

    const double result = vc > 0 ? value[vc - 1] : 0.0;

    free(value);
    free(opera);
    return result;
}

int main()
{
    wchar_t c[255];
    _getws_s(c, 255);
    const double result = AnalyticFormula(c);
    wprintf(L"%lf", result);
    return 0;