题目:设计一个模拟计算器的程序,要求能对包含加、减、乘、除、括号运算符及sqrt和abs函数的任意整数型表达式进行求解。(难易度90)
要求:要检查有关运算的条件,并对可能的错误产生报警。
实现效果:
实现:
两个顺序栈
扫描到数字:用j标记,实现多位数的情况运算完后再入栈
扫描到符号:符号栈为空,入栈
符号栈有操作符,比较优先级,新的运算符比栈顶运算符优先级高,进行运算,优先级低,运算符入栈,优先级相等,运算符出栈
小细节
负数的实现:起始位为“-”号,补0,左括号后紧接着“-”号,补0
用A代替abs绝对值函数
用S代替sqrt开平方根函数(不区分大小写)
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<stdbool.h>
#define MAX 1000
//数据栈
typedef struct NumStack{
double nums[MAX];
int top;
}NumStack;
//运算符栈
typedef struct OpStack{
char ops[MAX];
int top;
}OpStack;
//初始化
void init_Nums(NumStack *s){
s->top = -1;
}
void init_Ops(OpStack *s){
s->top = -1;
}
//入栈
bool push_Nums(NumStack *s,double val){
if(s->top == MAX-1){
printf("数据栈满\n");
exit(-1);
}
s->top++;
s->nums[s->top] = val;
return true;
}
bool push_Ops(OpStack *s,char ch){
if(s->top == MAX-1){
printf("运算符栈满\n");
exit(-1);
}
s->top++;
s->ops[s->top] = ch;
return true;
}
//出栈
bool pop_Nums(NumStack *s){
if(s->top == -1){
printf("数据栈空\n");
exit(-1);
}
s->top--;
return true;
}
bool pop_Ops(OpStack *s){
if(s->top == -1){
printf("运算符栈空\n");
exit(-1);
}
s->top--;
return true;
}
//取栈顶
double head_Nums(NumStack *s){
if(s->top == -1){
printf("数据栈空\n");
exit(-1);
}
return s->nums[s->top];
}
char head_Ops(OpStack *s){
if(s->top == -1){
printf("运算符栈空\n");
exit(-1);
}
return s->ops[s->top];
}
//运算
double calculate(double a,double b,char op){
double s = 0.0;
switch(op){
case '+': s = a+b; break;
case '-': s = a-b; break;
case '*': s = a*b; break;
case '/':
if(b == 0){
printf("ERROR:除数不能为0!\n");
exit(-1);
}else{
s = a/b;
}
break;
case 'A':case 'a': s = fabs(b); break;
case 'S':case 's':
if(b < 0){
printf("ERROR:平方根不能为负!\n");
exit(-1);
}else{
s = sqrt(b);
}
break;
}
printf("%.2lf %c %.2lf = %.2lf\n",a,op,b,s);
return s;
}
//判断运算符优先级
char Compare(char op1,char op2){
char tab[9][10] = {
{'>','>','<','<','<','>','<','<','>'},
{'>','>','<','<','<','>','<','<','>'},
{'>','>','>','>','<','>','<','<','>'},
{'>','>','>','>','<','>','<','<','>'},
{'<','<','<','<','<','=','<','<','E'},
{'>','>','>','>','E','>','>','>','>'},
{'>','>','>','>','<','>','>','>','>'},
{'>','>','>','>','<','>','>','>','>'},
{'<','<','<','<','<','E','<','<','='}
};
char op[10] = {'+','-','*','/','(',')','A','S','#'};
int x = 0,y = 0;
for(int i = 0;i<9;i++){
if(op[i] == op1) x = i;
if(op[i] == op2) y = i;
}
if(tab[x][y] == 'E'){
printf("输入表达式错误");
exit(-1);
}
return tab[x][y];
}
//检查表达式输入是否合法
bool check(char *s,int len){
int i = 0;
for(i;i<len;i++){
if(s[i]>='0' && s[i]<='9') continue;
if(s[i]=='(' || s[i]==')' || s[i]=='+' || s[i]=='-' || s[i]=='*' || s[i]=='/' || s[i]=='A' || s[i]=='a' || s[i]=='S' || s[i]=='s' || s[i]=='.') continue;
return false;
}
return true;
}
void changeCase(char *op){
if(*op == 'a')
*op = 'A';
if(*op == 's')
*op = 'S';
}
int main(int argc, const char* argv[])
{
char expre[100],num[100];
int len;
NumStack nstack;
OpStack ostack;
init_Nums(&nstack);
init_Ops(&ostack);
push_Ops(&ostack,'#');
printf("请输入表达式:\n");
scanf("%s",expre);
len = strlen(expre);
if(!check(expre,len)){
printf("输入的表达式不合法!\n");
exit(-1);
}
int i=0,j=0,k=0;
double x=0,y=0,temp = 0;
expre[len] = '#';
//起始为负数的情况
if(expre[0] == '-'){
push_Nums(&nstack,0);
}
for(i;i<=len;i++){
changeCase(&expre[i]);
if(expre[i]>='0' && expre[i]<='9' || expre[i]=='.'){
temp = temp*10+(expre[i]-48);//多位数
j = 1;
continue;
}
if(j){
push_Nums(&nstack,temp);
j=0;
temp = 0;
}
//左括号后紧接着是-号的是负数
if(expre[i]=='(' && expre[i+1]=='-'){
num[i+1] = 0;
push_Nums(&nstack,0);
}
switch(Compare(head_Ops(&ostack),expre[i])){
case '<':
push_Ops(&ostack,expre[i]);
break;
case '=':
pop_Ops(&ostack);
break;
case '>':
//abs和sqrt只需要出一个数据
if(head_Ops(&ostack)== 'A' || head_Ops(&ostack)== 'S'){
y = head_Nums(&nstack);
pop_Nums(&nstack);
push_Nums(&nstack,calculate(0,y,head_Ops(&ostack)));
}else{
y = head_Nums(&nstack);
pop_Nums(&nstack);
x = head_Nums(&nstack);
pop_Nums(&nstack);
push_Nums(&nstack,calculate(x,y,head_Ops(&ostack)));
}
pop_Ops(&ostack);
i--;
break;
}
}
double result = head_Nums(&nstack);
printf("该表达式的结果为:%.2lf",result);
return 0;
}
存在的问题:如果运算符在后,也可以进行运算,按正常情况应该报错,但是仍然进行运算了