简单计算器 考虑括号优先级 c语言

上课时我们老师布置的作业,不知道大家是不是也做过。第一次写考虑括号的计算器,把自己原本的代码优化了一下,拿出来与大家分享。

要求:

简单计算器,可以考虑优先级以及括号,括号可以嵌套,输出规格化。

思路:

将输入储存进一个字符串内,从左到右以此计算,分单元计算。比如,5*3+4/2*3+1+6*3中,5*3, 4/2*3,1,6*3分别为一个单元,遇到括号则将括号中的算是取出来,单独运算。最后得到的数通过加减结合在一起,即最终结果。

先获取第一个单独的数字,从字符串最左端向右,遇到加减号就停下来,加上计算出的数字,遇到除号或乘号就用手里的数做乘除计算,遇到括号就使用以上思路代码的递归计算成单独的数字。

代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int braLen(const char *c);    /*计算左括号到对应右括号的位数*/
double calculate(const char* c,int l);     /*运算函数*/
int main(){
	char c[1000]; 
	gets(c);
	int l = strlen(c);				/*获取输入的长度*/ 
	printf("%lg\n",calculate(c,l));    /*格式化输出*/ 
	return 0;
}
int braLen(const char *c)
{
	int n = 1 , y = 0;	//n为位数,如果输入合理至少也是2 
	if( c[0] != '(')
		return 1;
	while( y != 1 )
	{//此块内的代码相当于从左括号的下一位开始往后找 ,出现右括号使y+1,左括号-1,否则不变,以找到对应的右括号 
		y += ( c[n] == '(') ? -1 :  c[n] == ')' ;		/*也可以改成if else结构*/ 
		n++;
	}
	return n ;
}
double getFirst(const char* c)
{	
	if( c[0] == '(' )
		 return calculate(&c[1],braLen(&c[0])-2) ;
	else if( c[1] != '(' )
		return atof( &c[0] ) ;
	else
		return ( c[0] == '+' ) ? calculate(&c[2],braLen(&c[1])-2) : - calculate(&c[2],braLen(&c[1])-2) ;
}
double calculate(const char* c,int l)/*l为要计算算式的长度,以braLen得到括号中式子的长度*/ 
{
	double sum = 0 , n , number ;    /*num储存最终结果,n存储单元值,number为除数的值*/
	for(int i = 0 ; i < l ; )
	{//获取第一个值,括号中的式子计算最终值也算一个值	
		n = getFirst(&c[i]);
		if( ( c[i] == '+' || c[i] == '-') && ( c[i+1] == '+' || c[i+1] == '-') )
			n = ( c[i] == '+' ) ? getFirst( &c[i+1] ) : - getFirst( &c[i+1] );
		if( c[i] == '(' )
			i += braLen(&c[i]) - 1;
		while(1)
		{	
			while( ( c[i] == '*' || c[i] == '/' || c[i] == '+' || c[i] == '-' ) && (c[i+1] == '+' || c[i+1] == '-' ) ) i++;
			for( i += braLen(&c[i+1]) ; c[i] >= '0' && c[i] <= '9' || c[i] == '.'  ; i++ ) ;	//跳过一个数 
			if( c[i] == '+' || c[i] == '-' || i == l )	//遇到加减号或者已到式子结尾,表示一个单元结束,退出 
				break; 
			else if( c[i] == '*' || c[i] == '/' )		//表示未到下一个单元 
			{	
			    number = getFirst( &c[i+1] ) ;
			    if( c[i] == '*')
					n = n*number;
				else
				{
					if( number == 0 )
					{
						printf("出现除数为0不可计算的情况\n");exit(0);	//除数为0, 退出程序 
					} 
					n = n/number; 
				}	
			}
		}
		sum += n ;
	}
	return sum;
}

代码中已经可以在除数为0的情况下终止程序了,但如果想要检测输入式子是否合理,需要自己在运算前面加判断,并在式子不合理的情况下阻止输出,这里给出部分情况的检测代码。

	int i,zuo,you;
	zuo = you = 0;
	for( i = 0 ; i < l ; i++ )
	{
		if( !isf(c[i]) && c[i] != '(' && c[i] != ')' && !( c[i] >= '0' && c[i] <= '9'))
		{
			printf("存在非法字符\n");
			check++;break;
		}
		else if( c[i] == '(' )
			zuo++;
		else if( c[i] == ')' )
			you++;
		else if( isf(c[i]) && isf(c[i+1]) || c[0] == '*' || c[0] == '/')
		{
			printf("运算符不合理\n");
			check++;break; 
		}
		if( you > zuo )
		{
			printf("括号结构不合理\n"); 
			check++;break;
		}
		if( c[i] == '.' && ( !(c[i+1]>='0'&&c[i+1]<='9') || !(c[i-1]>='0'&&c[i-1]<='9') ))
		{
			printf("小数点处浮点数不合规则\n");
			 check++;break;
		}
	}
	if( zuo != you && check == 0)
	{
		printf("括号结构不合理\n");
		check++;
	}

	//输出 
	if( check == 0 )
		printf("%lg",yunsuan(c,l));
int isf(char c)
{
	if( c == '.' || c =='+' || c == '-' || c == '*' || c == '/'  )
		return 1;
	return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值