上课时我们老师布置的作业,不知道大家是不是也做过。第一次写考虑括号的计算器,把自己原本的代码优化了一下,拿出来与大家分享。
要求:
简单计算器,可以考虑优先级以及括号,括号可以嵌套,输出规格化。
思路:
将输入储存进一个字符串内,从左到右以此计算,分单元计算。比如,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;
}