C语言实现简单计算器程序
这两天在看一个C语言写的计算器程序,做了不少的功夫,跟着作者一步步的进行完善,了解了许多细节性的东西,在此自己做个总结,加深自己对程序的印象,也算是梳理。
在该计算器程序,能进行加减乘除、sin、cos、exp等操作,同时能进行数值保存功能。而该计算器使用逆波兰表示法。即所有运算符都跟在操作数的后面,比如下列表达式:
(1-2)*(4+5)采用逆波兰表示法表示为:12-45+*
逆波兰表达法中不需要圆括号,只要知道每个运算符需要几个操作数就不会引起歧义。
计算器程序实现很简单,具体原理如下:
while(/*下一个运算符或操作数不是文件结束指示符*/) if(/*是数*/) /*将该数压入到栈中*/ elseif(/*是运算符*/) /*弹出所需数目的操作数*/ /*执行运算*/ /*将结果压入到栈中*/ elseif(/*是换行符*/) /*弹出并打印栈顶的值*/ else /*出错*/
在程序设计中,使用模块化思想,getop函数来进行读入,该函数返回一个标识,用来标识读入的是什么类型。主循环体中根据该标识执行相应的动作。
以下是该程序:(我将所有函数和变量放在同一文件)
#include#include #include #defineMAXOP100 #defineNUMBER'0'//标识读入的是数字 #defineNAME'n'//标识读入的是字符串(函数名或非法字符串) #defineALPHA26 intgetop(char[]); voidpush(double);//压栈 doublepop(void);//出栈 voidclear(void);//清空栈 voidmathfnc(char[]);//执行相应的数学函数sin、cos、exp等 intmain(void) { inttype; inti,var=0; doubleop1,op2,v; chars[MAXOP]; doublevariable[ALPHA]; for(i=0;i ='A'&&var<='Z') variable[var-'A']=pop(); else printf("error:novariablename\n"); break; case'c': clear(); break; case'd'://复制栈顶元素 op2=pop(); push(op2); push(op2); break; case's'://交换栈元素 op1=pop(); op2=pop(); push(op1); push(op2); case'\n': v=pop();//v保存最后的一次结果 printf("\t%.8g\n",v); break; default: if(type>='A'&&type<='Z') push(variable[type-'A']); elseif(type=='@')//输入的字符@表示最近一次结果值 push(v); else printf("error:unknowncommand%s\n",s); break; } var=type; } return0; } /*-----------------------------------------------------------*/ #defineMAXVAL100 intsp=0;//标识栈顶 doubleval[MAXVAL]; voidpush(doublef) { if(sp 0) returnval[--sp]; else { printf("error:statckempty\n"); return0.0; } } voidclear(void) { sp=0; } voidmathfnc(chars[]) { doubleop2; if(strcmp(s,"sin")==0) push(sin(pop())); elseif(strcmp(s,"cos")==0) push(cos(pop())); elseif(strcmp(s,"exp")==0) push(exp(pop())); elseif(strcmp(s,"pow")==0) { op2=pop(); push(pow(pop(),op2)); } else printf("error:%snotsupported\n",s); } /*-----------------------------------------------------------*/ #include intgetch(void); voidungetch(int); intgetop(chars[]) { inti,c; while((s[0]=c=getch())==''||c=='\t')//过滤开头的空白字符 ; s[1]='\0'; i=0; if(islower(c))//判断是否为小写字母,也即读取由小写字母组成的字符串 { while(islower(s[++i]=c=getch())) ; s[i]='\0'; if(c!=EOF) ungetch(c); if(strlen(s)>1) returnNAME; else returnc; } if(!isdigit(c)&&c!='.'&&c!='-') returnc; if(c=='-')//用于判断是负数还是减操作 { if(isdigit(c=getch())||c=='.') s[++i]=c; else { if(c!=EOF) ungetch(c); return'-'; } } if(isdigit(c))//收集整数部分 while(isdigit(s[++i]=c=getch())) ; if(c=='.')//收集小数部分 while(isdigit(s[++i]=c=getch())) ; s[i]='\0'; if(c!=EOF) ungetch(c); returnNUMBER; } /*-----------------------------------------------------------*/ /* *引用以下两个函数是因为:程序不能确定它已经读入的输入是否足够* *除非超前多读入一些输入,在本程序中,读入一些字符合成一个数字* *所以在看到第一个非数字字符之前,已经读入的数的完整性是不能确定的 *由于程序要超前读入一个字符,这样就导致最后又一个字符不属于当前所要读入的数 */ #defineBUFSIZE100 charbuf[BUFSIZE]; intbufp=0; intgetch(void) { return(bufp>0)?buf[--bufp]:getchar(); } voidungetch(intc) { if(bufp>=BUFSIZE) printf("ungetch:toomanycharacters\n"); else buf[bufp++]=c; }
该程序虽然简单,但是还是存在一些小小的问题,比如没有数据时进行pop的话,会打印栈中无数据同时返回数值0.0,在循环体中许多执行操作会将该数值保存到栈中,之后打印该值,用户体验度比较差。程序设计方面,模块化设计使得该程序容易增加功能而不影响其他模块,比如增加一些数学函数处理,在mathfnc函数中去添加,或增加一些运算符操作,可以在主循环体中增加。
总之,这次学习还是颇有收获。
关于计算器的精彩文章请查看《计算器专题》,更多精彩等你来发现!
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。