1.实验需求
请按照四则运算加、减、乘、除、幂(^)和括号的优先关系和惯例,编写计算器程序。要求:
- 从键盘输入一个完整的表达式,以回车作为表达式输入结束的标志。
- 输入表达式中的数值均为大于等于零的整数。中间的计算过程如果出现小数也只取整。
例如,输入:4+2*5= 输出:14
输入:(4+2)*(2-10)= 输出:-48
2.概要设计
(1)抽象数据类型的定义:
采用两种栈(符号栈和数字栈)分别存储运算符和数字
两种栈都有各自的初始化、push、pop等函数
typedef struct{//符号栈
char *base;
char *top;
int stacksize;
}Opstack;
typedef struct{//数字栈
int *base;
int *top;
int stacksize;
}Numstack;
(2)主程序流程
主函数main
先定义栈符号栈和数字栈,定义一个数组ch临时存储输入的计算式初始化符号栈schar,调用PushOp函数在栈底放一个’=’,初始化数字栈snum,调用gets函数,将表达式临时存储在数组ch里,求数组长度。
在while循环(ch数组不到最后一个=或者schar不到栈底=)中,先判断现在所指数组元素是数字还是符号,如果是数字,调用Num函数将char型数字转换成int型,并将数字存储进数字栈,数组指针移动。如果是符号,调用Precede函数比较它和符号栈栈顶元素的优先级,如果栈顶元素优先级小于现在数组里的运算符,将该运算符进栈,移动数组指针;如果等于,栈顶元素出栈;如果大于,取数字栈栈顶两个元素,和符号栈栈顶元素,进行计算,再将结果压入数字栈。
循环结束,输出数字栈栈顶元素,即为结果。
(3)各模块介绍
由主程序main依次调用:
- int InitOpStack(Opstack &s)符号栈初始化函数
- int PushOp(Opstack &s, char e)符号栈进栈函数
- int InitNumStack(Numstack &s)数字栈初始化函数
- char GetTopOp(Opstack &s)符号栈取栈顶函数
- int In(char c)判断是运算符还是数字函数
- int Getnum(char ch[], int j)数组中char型数字转int型函数
- int PushNum(Numstack &s, int e)数字栈进栈函数
- char Precede(char c1, char c2)运算符优先级判断函数
- int PopOp(Opstack &s, char &e)符号栈pop函数
- int PopNum(Numstack &s, int &e)数字栈pop函数
- int Operate(int a, char theta, int b)运算函数
3.详细设计
(1)主函数main:
int main(){//主函数
Opstack schar;
Numstack snum;
char ch[100],x,theta;
int a,b;
int Num;
int l;
InitOpStack(schar);
PushOp(schar,'=');//栈底压一个=
InitNumStack(snum);
gets(ch);//把式子先存进去了
l=strlen(ch);
while(ch[i]!='=' || GetTopOp(schar)!='=')
{
if(!In(ch[i])){//判断输入的是数字
Num=Getnum(ch,i);
PushNum(snum, Num);
}
else{
switch(Precede(GetTopOp(schar),ch[i])){
case '<':
PushOp(schar,ch[i]);
i++;
break;
case '=':
PopOp(schar, x);
i++;
break;
case '>':
PopOp(schar, theta);
PopNum(snum, b);
PopNum(snum, a);
PushNum(snum,Operate(a, theta, b));
break;
}
}
}
printf("%d", GetTopNum(snum));
return 0;
}
(2)数字栈的基本操作函数
int InitNumStack(Numstack &s){//创建数字栈
s.base = (int *)malloc(STACK_INIT_SIZE * sizeof(int));
if(!s.base) exit(OVERFLOW);
s.top = s.base;
s.stacksize = STACK_INIT_SIZE;
return OK;
}
int PushNum(Numstack &s, int e){//数字栈push函数
if(s.top - s.base >= s.stacksize){
s.base = (int *)realloc(s.base, (s.stacksize + STACKINCREMENT) * sizeof(int));
if (!s.base) exit(OVERFLOW);
s.top = s.base + s.stacksize;
s.stacksize += STACKINCREMENT;
}
*s.top++=e;
return OK;
}
int PopNum(Numstack &s, int &e){//数字栈pop函数
if(s.top == s.base) return ERROR;
e = *--s.top;
return OK;
}
int GetTopNum(Numstack &s){//数字栈取栈顶
int e;
if(s.top == s.base) return ERROR;
e = *(s.top-1);
return e;
}
(3)符号栈的基本操作函数
int InitOpStack(Opstack &s){//创建符号栈
s.base = (char *)malloc(STACK_INIT_SIZE * sizeof(char));
if(!s.base) exit(OVERFLOW);
s.top = s.base;
s.stacksize = STACK_INIT_SIZE;
return OK;
}
int PushOp(Opstack &s, char e){//符号栈push函数
if(s.top - s.base >= s.stacksize){
s.base = (char *)realloc(s.base, (s.stacksize + STACKINCREMENT) * sizeof(char));
if (!s.base) exit(OVERFLOW);
s.top = s.base + s.stacksize;
s.stacksize += STACKINCREMENT;
}
*s.top++=e;
return OK;
}
int PopOp(Opstack &s, char &e){//符号栈pop函数
if(s.top == s.base) return ERROR;
e = *--s.top;
return OK;
}
char GetTopOp(Opstack &s){//符号栈取栈顶
char e;
if(s.top == s.base) return ERROR;
e = *(s.top-1);
return e;
}
(4)判断数组中char型是运算符还是数字函数
int In(char c)//判断是数字还是符号
{
if(c=='+'||c=='-'||c=='*'||c=='/'||c=='('||c==')'||c=='^'||c=='\n'||c=='=')
return 1;
else return 0;
}
(5)运算函数
int Operate(int a, char theta, int b){//运算函数
int num=0;
switch(theta){
case '+': num=a+b; break;
case '-': num=a-b; break;
case '*': num=a*b; break;
case '/': num=a/b; break;
case '^':
num = 1;
while(b!=0)
{
num *= a;
b--;
}
break;
}
return num;
}
(6)运算符优先级比较函数
输入两个运算符,运用二维数组构造一个类似表格一样结构查询两个运算符之间的关系,返回<,>,=
char Precede(char c1, char c2){//查表比较优先级
char levelTable[] = { '+', '-', '*', '/','^', '(',')','='};
int m,n;
char ch[8][8]={//查表!!!
{'>','>','<','<','<','<','>','>'},
{'>','>','<','<','<','<','>','>'},
{'>','>','>','>','<','<','>','>'},
{'>','>','>','>','<','<','>','>'},
{'>','>','>','>','>','<','>','>'},
{'<','<','<','<','<','<','=',' '},
{'>','>','>','>','>',' ','>','>'},
{'<','<','<','<','<','<',' ','='}
};
for(m=0;m<8;m++)
{
if(c1==levelTable[m]) break;
}
for(n=0;n<8;n++)
{
if(c2==levelTable[n]) break;
}
return ch[m][n];
}
(7)char型转Int型函数
只要下一位还是数字,这个函数就会把数组里的数字组合成Int型的数字
4.总代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
int i=0;//全局变量,用于判断字符是否全部进栈
typedef struct{//符号栈
char *base;
char *top;
int stacksize;
}Opstack;
typedef struct{//数字栈
int *base;
int *top;
int stacksize;
}Numstack;
int InitOpStack(Opstack &s){//创建符号栈
s.base = (char *)malloc(STACK_INIT_SIZE * sizeof(char));
if(!s.base) exit(OVERFLOW);
s.top = s.base;
s.stacksize = STACK_INIT_SIZE;
return OK;
}
int InitNumStack(Numstack &s){//创建数字栈
s.base = (int *)malloc(STACK_INIT_SIZE * sizeof(int));
if(!s.base) exit(OVERFLOW);
s.top = s.base;
s.stacksize = STACK_INIT_SIZE;
return OK;
}
int PushOp(Opstack &s, char e){//符号栈push函数
if(s.top - s.base >= s.stacksize){
s.base = (char *)realloc(s.base, (s.stacksize + STACKINCREMENT) * sizeof(char));
if (!s.base) exit(OVERFLOW);
s.top = s.base + s.stacksize;
s.stacksize += STACKINCREMENT;
}
*s.top++=e;
return OK;
}
int PushNum(Numstack &s, int e){//数字栈push函数
if(s.top - s.base >= s.stacksize){
s.base = (int *)realloc(s.base, (s.stacksize + STACKINCREMENT) * sizeof(int));
if (!s.base) exit(OVERFLOW);
s.top = s.base + s.stacksize;
s.stacksize += STACKINCREMENT;
}
*s.top++=e;
return OK;
}
int PopOp(Opstack &s, char &e){//符号栈pop函数
if(s.top == s.base) return ERROR;
e = *--s.top;
return OK;
}
int PopNum(Numstack &s, int &e){//数字栈pop函数
if(s.top == s.base) return ERROR;
e = *--s.top;
return OK;
}
int In(char c)//判断是数字还是符号
{
if(c=='+'||c=='-'||c=='*'||c=='/'||c=='('||c==')'||c=='^'||c=='\n'||c=='=')
return 1;
else return 0;
}
char GetTopOp(Opstack &s){//符号栈取栈顶
char e;
if(s.top == s.base) return ERROR;
e = *(s.top-1);
return e;
}
int GetTopNum(Numstack &s){//数字栈取栈顶
int e;
if(s.top == s.base) return ERROR;
e = *(s.top-1);
return e;
}
int Operate(int a, char theta, int b){//运算函数
int num=0;
switch(theta){
case '+': num=a+b; break;
case '-': num=a-b; break;
case '*': num=a*b; break;
case '/': num=a/b; break;
case '^':
num = 1;
while(b!=0)
{
num *= a;
b--;
}
break;
}
return num;
}
char Precede(char c1, char c2){//查表比较优先级
char levelTable[] = { '+', '-', '*', '/','^', '(',')','='};
int m,n;
char ch[8][8]={//查表!!!
{'>','>','<','<','<','<','>','>'},
{'>','>','<','<','<','<','>','>'},
{'>','>','>','>','<','<','>','>'},
{'>','>','>','>','<','<','>','>'},
{'>','>','>','>','>','<','>','>'},
{'<','<','<','<','<','<','=',' '},
{'>','>','>','>','>',' ','>','>'},
{'<','<','<','<','<','<',' ','='}
};
for(m=0;m<8;m++)
{
if(c1==levelTable[m]) break;
}
for(n=0;n<8;n++)
{
if(c2==levelTable[n]) break;
}
return ch[m][n];
}
int Getnum(char ch[], int j){//字符串转数字
int num=ch[j]-48;
j++;
while(ch[j]>='0'&&ch[j]<='9')//处理多位数字
num=num*10+ch[j++]-48;
i=j;//处理到第几位了
return num;
}
int main(){//主函数
Opstack schar;
Numstack snum;
char ch[100],x,theta;
int a,b;
int Num;
int l;
InitOpStack(schar);
PushOp(schar,'=');//栈底压一个=
InitNumStack(snum);
gets(ch);//把式子先存进去了
l=strlen(ch);
while(ch[i]!='=' || GetTopOp(schar)!='=')
{
if(!In(ch[i])){//判断输入的是数字
Num=Getnum(ch,i);
PushNum(snum, Num);
}
else{
switch(Precede(GetTopOp(schar),ch[i])){
case '<':
PushOp(schar,ch[i]);
i++;
break;
case '=':
PopOp(schar, x);
i++;
break;
case '>':
PopOp(schar, theta);
PopNum(snum, b);
PopNum(snum, a);
PushNum(snum,Operate(a, theta, b));
break;
}
}
}
printf("%d", GetTopNum(snum));
return 0;
}