计算器支持 四则运算、圆括号;整数、小数、正负号;省略括号间'*'、括号内只有数字
#include<stdio.h>
#include<stdlib.h>
//栈定义
struct Num //数字栈
{
float num[100]; //栈
int top; //栈顶(元素个数)
};
struct Cal //符号栈
{
char cal[100];
int top;
};
//入栈
void InNum(struct Num *n, float num)
{
n->top++;
n->num[n->top] = num;
}
void InCal(struct Cal *c, char cha)
{
c->top++;
c->cal[c->top] = cha;
}
//出栈
float OutNum(struct Num *n)
{
float num = n->num[n->top];
n->top--;
return num;
}
char OutCal(struct Cal *c)
{
char cha = c->cal[c->top];
c->top--;
return cha;
}
//读栈顶
float GetNum(struct Num *n)
{
return n->num[n->top];
}
char GetCal(struct Cal *c)
{
return c->cal[c->top];
}
//初始化双栈
void InitStacks(struct Num *n, struct Cal *c)
{
n->top = -1;
c->top = -1;
}
//输出错误信息 *剩下的错误情况在errofunc()中
int erro(int e)
{
switch (e)
{
case 1:
printf("***ILLEGAL CHARACTORS***\n");
break;
case 2:
printf("***DO NOT ENTER CONSEQUTIVE CALCULATION SYMBOLS***\n");
break;
case 3:
printf("***DO NOT TREAT ZERO AS A DIVISOR!***\n");
break;
case 4:
printf("***PLEASE INPUT SOMETIONG***\n");
break;
case 5:
printf("***BRACKETS DO NOT MATCH EACHOTHERS***\n");
break;
case 6:
printf("***INVALID INPUT***\n");
break;
default:
break;
}
fflush(stdin);
return 1;
}
//获取输入的表达式并进行合法性检查
int GetString(char *str)
{
char c;
int i = 0;
int e = 0;
int b[2] = {0};
printf("PLEASE ENTER THE ARITHMETIC EXPRESSION WITH \nintengers, floats AND '+' '-' '*' '/' '(' ')' \n");
while((c = getchar()) != '\n')
{
str[i] = c;
if(!((c >= '0' && c <= '9') || c == '.' || c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')')) //非法字符
{
return erro(1);
}
if( i>0 && (str[i-1] == '+' || str[i-1] == '-' || str[i-1] == '*' || str[i-1] == '/' || str[i-1] == '.')
&& (str[i]== '+' || str[i] == '-' || str[i] == '*' || str[i] == '/'|| str[i] == '.' || str[i] == ')')) //连续运算符
{
return erro(2);
}
if( i>1 && str[i-2] == '/' && str[i-1] == '0' && (str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/')) //零作除数
{
return erro(3);
}
if(c == '(')
{
b[0]++;
}
else if(c == ')')
{
b[1]++;
}
i ++;
}
if(*str == '\0') //输入空字符串
{
return erro(4);
}
if(b[0] != b[1]) //括号不匹配
{
return erro(5);
}
if(str[i-1] =='+' || str[i-1] == '-' || str[i-1] == '*' || str[i-1] == '/')
{
return erro(6); //最后一位字符是算术运算符
}
str[i] = '\0';
return 0;
}
//声明错误函数
void errofunc(struct Num *n, struct Cal *c,char *str,int e);
// void erro0( struct Num *n, struct Cal *c,char *str,void (*errofunc)(struct Num *, struct Cal *,char *,int))
// {
// errofunc(n,c,str,1);
// }
//算术运算
float Compute(float n1, float n2, char cha, struct Num *n, struct Cal *c,char *str)
{
float result;
switch(cha)
{
case'+':
result = n1 + n2;
break;
case '-' :
result = n1 - n2;
break;
case '*' :
result = n1 * n2;
break;
case '/' :
if(n2 == 0)
errofunc(n,c,str,1);
result = n1 / n2;
break;
default:
break;
}
return result;
}
//进行一次运算
void GetAnswer(struct Num *n, struct Cal *c,char *str)
{
if((n->top<0) || (c->top<0))
{
errofunc(n,c,str,2); //出现数据栈或符号栈为空的错误
}
if(GetCal(c) == '(') //括号内只有数字的情况
{
return;
}
float n2 = OutNum(n);
float n1 = OutNum(n);
InNum(n, Compute(n1,n2,OutCal(c),n,c,str));
}
/*
边解析算式、边压栈、边计算出栈
压栈、计算、出栈交替进行,直到算式被解析完
或者解析过程中发现不合法终止为止
*/
void ExpressionToStack(struct Num *n, struct Cal *c, char *s)
{
int tn = 0; //tn,t 存储临时数据
char t[100] = {0};
for(int i = 0; s[i-1] != '\0' ; i++)
{
/***************************************处理数字*******************************************/
if(i == 0 && (s[i] == '-' || s[i] == '+')) //负号
{
t[tn++] = s[i];
}
else if(s[i] == '(' && (s[i+1] == '-' || s[i+1] == '+')) //左括号和负号
{
i++;
t[tn++] = s[i++];
while(s[i] >= '0' && s[i] <= '9' || s[i] == '.')
{
t[tn] = s[i];
tn++;
i++;
}
InNum(n, atof(t));
for(tn; tn >= 0; tn--)
{
t[tn] = 0;
}
tn++;
if(s[i] != ')')
{
i--;
InCal(c, '(');
}
}
else if(s[i] >= '0' && s[i] <= '9' || s[i] == '.') //数字
{
while(s[i] >= '0' && s[i] <= '9' || s[i] == '.')
{
t[tn] = s[i];
tn++;
i++;
}
InNum(n, atof(t));
for(tn; tn >= 0; tn--)
{
t[tn] = 0;
}
tn++;
i--;
}
/***************************************处理符号*******************************************/
else if(c->top == -1) //还没有任何符号,直接入符号栈
{
InCal(c, s[i]);
}
else if(s[i] == '(') //左括号直接入栈,如果是右括号之后的左括号,入栈*后再入栈'('
{
if(s[i-1] == ')')
{
InCal(c, '*');
InCal(c, s[i]);
}
else
{
InCal(c, s[i]);
}
}
else if(s[i] == ')') //右括号,计算出栈直到左括号
{
do
{
GetAnswer(n,c,s);
}
while(c->cal[c->top] != '(');
OutCal(c);
}
/*加减号和结束*/
else if(s[i] == '+' || s[i] == '-' || s[i] == '\0')
{
if(GetCal(c) == '(') //符号栈顶是左括弧直接入栈
{
InCal(c, s[i]);
}
else if(GetCal(c) == '+' || GetCal(c) == '-' //符号栈顶是其他符号计算循环出栈后再进栈
|| GetCal(c) == '*' || GetCal(c) == '/')
{
while(c->top >= 0 && n->top >= 0 && GetCal(c) != '(')
{
GetAnswer(n,c,s);
}
InCal(c,s[i]);
}
}
/*乘除号*/
else if(s[i] == '*' || s[i] == '/')
{
if(GetCal(c) == '(' || GetCal(c) == '+' || GetCal(c) == '-') //栈顶是左括弧,加减号直接入栈
{
InCal(c, s[i]);
}
else if(GetCal(c) == '*' || GetCal(c) == '/') //栈顶是乘除号计算到上一个加减号或者左括号 再进栈
{
while(c->top >= 0 && n->top >= 0 && GetCal(c) != '(' && GetCal(c) != '+' && GetCal(c) != '-')
{
GetAnswer(n,c,s);
}
InCal(c,s[i]);
}
}
}
printf("%g\n",n->num[0]);
}
void calculate()
{
struct Num num;
struct Cal cal;
InitStacks(&num, &cal);
char *str = (char *)calloc(200,sizeof(char));
if( str == NULL )
{
fprintf(stderr, "Error - unable to allocate required memory\n");
getchar();
return;
}
if(GetString(str) == 0)
{
ExpressionToStack(&num, &cal, str);
}
free(str);
/*上一次计算结束 或者上一次输入不合法 询问是否进入下一次计算*/
printf("CONTINUE CALCULATING? y/n \n");
char c = getchar();
if(c == 'y' || c == 'Y')
{
printf("\n\n");
fflush(stdin);
calculate();
}
return;
}
//隐式报错
void errofunc( struct Num *n, struct Cal *c,char *str,int e)
{
switch(e)
{
case 1:
printf("***DO NOT TREAT ZERO AS A DIVISOR!***\n");
break;
case 2:
printf("***INVALID EXPRESSION***\n");
break;
default:
break;
}
free(str);
fflush(stdin);
while(n->top != -1)
{
OutNum(n);
}
while(c->top != -1)
{
OutCal(c);
}
printf("CONTINUE CALCULATING? y/n \n");
char cha = getchar();
if(cha == 'y' || cha == 'Y')
{
printf("\n\n");
fflush(stdin);
calculate();
}
exit(0);
}
int main(void)
{
calculate();
return 0;
}