编程挑战-简易计算器程序的编制
简易计算器功能要求:输入二个实数
及“+、-、*、/”,计算他们的结果并输出结果,同时,在屏幕上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;