简单计算器

一、需求分析

项目:简单计算器。
请按照四则运算加、减、乘、除、幂(^)和括号的优先关系和惯例,编写计算器程序。
要求:
① 从键盘输入一个完整的表达式,以回车作为表达式输入结束的标志。
② 输入表达式中的数值均为大于等于零的整数。中间的计算过程如果出现小数也只取整。
例如,
输入:4+2*5=
输出:14

输入:(4+2)*(2-10)=
输出:-48


二、概要设计

  1. 程序中用到的抽象数据类型的定义:
typedef struct
{	//数字栈结构体  
	int data[MAXSIZE];
	int top; 
}Snum;

typedef struct
{	//符号栈结构体 
	char op[MAXSIZE];
	int top;
}Sop;
  1. 主程序的流程:
    首先读取表达式,判断表达式是否合理。如果不合理,则输出“表达式输入有误!”如果合理,则初始化两个栈,一个是数字栈存放数字,一个是符号栈存放运算符号,再使用Calculator()函数计算表达式,得出结果。
int main()
{
	char e[MAXSIZE];	//定义一个数组存放表达式
	fgets(e, MAXSIZE-1, stdin);	//读入表达式 
	
	if(!judge(e))
	{
		Snum *n;	//数字栈
		Sop *o;		//符号栈
		InitSnum(&n);	//初始化数字栈和符号栈
		InitSop(&o);
		//表达式合理则计算
		Calculator(n, o, e);
		return 0;
	}
	else 
	{
		printf("表达式输入有误!\n");
		return 0;
	}
}

三、详细设计

核心算法是Calculator()函数,输入数字栈和符号栈,以及需要计算的表达式,依次读取表达式中的字符
①当遇到空格和左括号时跳过,左括号存入符号栈;
②用isdigit函数判断是否是数字,存入数字栈;
③如果不是数字,是右括号,因为已经判断表达式合理,所以直接计算,当符号栈顶不是左括号,说明有其他计算符号,出栈并将数字栈的上面两个数字进行运算,再将运算结果存入数字栈顶,最后将左括号出栈。
④当e[i]不是以上三种情况,说明是运算符号,比较其与运算符栈顶符号优先级,如果e更高级,则直接入栈,否则将符号栈顶元素出栈并运算。即要先计算优先级高的运算。
存放完e[i]后,检查运算符栈,如果不为空,则出栈计算。

void Calculator(Snum *n, Sop *o, char *e)
{
	int i;
	//当遇到空格和左括号跳过
	for(i = 0; i < strlen(e) && e[i] != '='; i++)
	{
		if(e[i] == ' ') continue;
		if(e[i] == '(') o->op[++o->top] = e[i];
		else if(isdigit(e[i]))	//用isdigit函数判断是否是数字 
		{
			int a = 0;
			while(i < strlen(e) && isdigit(e[i]))	//输入多位数 
			{
				a = (a * 10) + (e[i] - '0');
				i++;
			}
			i--;
			n->data[++n->top] = a;
		}
		else if(e[i] == ')')
		{
			while(o->top!=-1 && o->op[o->top] != '(')
			{
				int a2 = n->data[n->top--];
				int a1 = n->data[n->top--];
				char opn = o->op[o->top--];
				n->data[++n->top] = Op(a1, a2, opn);
			}
			if(o->top != -1) o->top--; 
			
		}
		else
		{
			Priorityop(n, o, e[i]);
			o->op[++o->top] = e[i];
		}
	}
	while(o->top != -1)
	{
		int a2 = n->data[n->top--];
		int a1 = n->data[n->top--];
		char opn = o->op[o->top--];
		n->data[++n->top] = Op(a1, a2, opn);
	}
	printf("%d\n", n->data[n->top]);
}

其他函数:

  1. 运算函数,计算简单加减乘除乘方的值:
Status Op(int a, int b, char op)
{	//运算 
	switch(op)
	{
		case '+': return a + b;
		case '-': return a - b;
		case '*': return a * b;
		case '/': return b ? a / b : 0;
		case '^': return (int)pow(a, b);
		default: return 0;
	}
}
  1. 判断符号优先级函数,以便判断运算符号是否入符号栈。并判断是否进行运算。
Status Priority(char op)
{	//判断符号优先级 
	if(op == '+' || op == '-') return 1;
	if(op == '*' || op == '/') return 2;
	if(op == '^') return 3;
	return 0;
}
Status Priorityop(Snum *n, Sop *o, char e)
{	//比较符号优先级,如果e更高级,则直接入栈,
	//否则将符号栈顶元素出栈并运算 
	while(Priority(o->op[o->top]) >= Priority(e))
	{
		int a2 = n->data[n->top--];
		int a1 = n->data[n->top--]; 
		char opn = o->op[o->top--];
		n->data[++n->top] = Op(a1, a2, opn);
	}
}

四、调试分析

不足:该程序一开始并没有设置算法来判断输入表达式是否合法,当输入不合法表达式,如:

①输入不合法字符
如中文字符、英文字母、其他特殊符号,即在{+, -, *, /, ^, (, )}和 0-9 数字之外的其他字符,均无输出。
输入:a+1=
输出:
不合法表达式举例1
②输入不合法运算符号
如括号不匹配,+ - * / 位置不对,均输出错误。
在这里插入图片描述
在这里插入图片描述
所以需要函数来判断输入表达式是否合法。

//判断表达式是否合理
Status judge(char e[])
{
	if(e[0] == '/' || e[0] == '*')
		return 0;
	if(e[strlen(e)-1] < '0' && e[strlen(e)-1 > '9'])
		return 0;
	
	int flag = 0;	//记录括号数量 
	for(int i = 0; i < strlen(e); i++)
	{
		if(e[i] == '(')
		{
			if(i == 0 && (e[i+1]=='*' || e[i+1] == '/'))
				return 0;
			else if(e[i-1]>='0' && e[i-1]<='9')
				return 0;
			flag++;
		}
		else if(e[i]==')')
		{
			if(i == 0)	return 0;
			else if(e[i-1] == '+' || e[i-1]=='*' || e[i-1]=='-' || e[i-1]=='/')
				return 0;
			else if(e[i+1]>='0' && e[i+1]<='9')
				return 0;
			flag--;
		}
	}
	if(flag == 0)	return 1;
	return 0;
}

五、测试结果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


附录

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <math.h>
#define MAXSIZE 100
typedef int Status;

typedef struct
{	//数字栈结构体  
	int data[MAXSIZE];
	int top; 
}Snum;

void InitSnum(Snum **N)
{	//初始化数据栈 
	*N = (Snum *)malloc(sizeof(Snum));
	(*N)->top = -1;
}

typedef struct
{	//符号栈结构体 
	char op[MAXSIZE];
	int top;
}Sop;

void InitSop(Sop **o)
{	//初始化符号栈 
	*o = (Sop *)malloc(sizeof(Sop));
	(*o)->top = -1;
}

//判断表达式是否合理
Status judge(char e[])
{
	if(e[0] == '/' || e[0] == '*' || e[0] == '+' || e[0] == '-')
		return 0;
	if(e[strlen(e)-2] < '0' && e[strlen(e)-2 > '9'])
		return 0;
	
	int flag = 0;	//记录括号数量 
	for(int i = 0; i < strlen(e); i++)
	{
		if(e[i] == '(')
		{
			if(i == 0 && (e[i+1]=='*' || e[i+1] == '/'))
				return 0;
			else if(e[i-1]>='0' && e[i-1]<='9')
				return 0;
			flag++;
		}
		else if(e[i]==')')
		{
			if(i == 0)	return 0;
			else if(e[i-1] == '+' || e[i-1]=='*' || e[i-1]=='-' || e[i-1]=='/')
				return 0;
			else if(e[i+1]>='0' && e[i+1]<='9')
				return 0;
			flag--;
		}
	}
	if(flag == 0)	return 1;
	return 0;
}

Status Op(int a, int b, char op)
{	//运算 
	switch(op)
	{
		case '+': return a + b;
		case '-': return a - b;
		case '*': return a * b;
		case '/': return b ? a / b : 0;
		case '^': return (int)pow(a, b);
		default: return 0;
	}
}

Status Priority(char op)
{	//判断符号优先级 
	if(op == '+' || op == '-') return 1;
	if(op == '*' || op == '/') return 2;
	if(op == '^') return 3;
	return 0;
}

Status Priorityop(Snum *n, Sop *o, char e)
{	//比较符号优先级,如果e更高级,则直接入栈,
	//否则将符号栈顶元素出栈并运算 
	while(Priority(o->op[o->top]) >= Priority(e))
	{
		int a2 = n->data[n->top--];
		int a1 = n->data[n->top--]; 
		char opn = o->op[o->top--];
		n->data[++n->top] = Op(a1, a2, opn);
	}
}

void Calculator(Snum *n, Sop *o, char *e)
{
	int i;
	for(i = 0; i < strlen(e) && e[i] != '='; i++)
	{
		if(e[i] == ' ') continue;
		if(e[i] == '(') o->op[++o->top] = e[i];
		else if(isdigit(e[i]))	//用isdigit函数判断是否是数字 
		{
			int a = 0;
			while(i < strlen(e) && isdigit(e[i]))	//输入多位数 
			{
				a = (a * 10) + (e[i] - '0');
				i++;
			}
			i--;
			n->data[++n->top] = a;
		}
		else if(e[i] == ')')
		{
			while(o->top!=-1 && o->op[o->top] != '(')
			{
				int a2 = n->data[n->top--];
				int a1 = n->data[n->top--];
				char opn = o->op[o->top--];
				n->data[++n->top] = Op(a1, a2, opn);
			}
			if(o->top != -1) o->top--; 
			
		}
		else
		{
			Priorityop(n, o, e[i]);
			o->op[++o->top] = e[i];
		}
	}
	while(o->top != -1)
	{
		int a2 = n->data[n->top--];
		int a1 = n->data[n->top--];
		char opn = o->op[o->top--];
		n->data[++n->top] = Op(a1, a2, opn);
	}
	printf("%d\n", n->data[n->top]);
}

int main()
{
	char e[MAXSIZE];	//定义一个数组存放表达式
	fgets(e, MAXSIZE-1, stdin);	//读入表达式 
	
	if(judge(e))
	{
		Snum *n;	//数字栈
		Sop *o;		//符号栈
		InitSnum(&n);	//初始化数字栈和符号栈
		InitSop(&o);
		//表达式合理则计算
		Calculator(n, o, e);
		return 0;
	}
	else 
	{
		printf("表达式输入有误!\n");
		return 0;
	}
}

注:初学者,借鉴许多前辈经验,欢迎指正交流!

  • 17
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值