C编程案例入门计算器之一般实现
上一节我们基本完成了界面设计和事件响应,这次我们继续来丰富功能。
我先讲按正常的思路来实现。
比如这样的字符输入1111
用我们人眼人脑来计算,一看就是连加连减,而且还可以做简便运算,110就消了,结果就是112,非常容易。
但要想让程序读懂并且能够计算正确,却不是一件容易的事,它就相当于是个刚出生的婴儿,你得教它怎么做。
仅针对这个输入,我的思路是设置一个结果变量分别为result,初始值为0,还要记录一个上一次的符号变量lastoperator,然后不断循环,找到每一个数字,用result和lastoperator去跟这个数字做运算。大概需要这样的步骤:循环处理每个字符;如果是数字,则附加到一个变量保存;如果是运算符,将前面保存的变量转换成数字,然后用lastoperator跟result做运算,更新result值,重置变量为空;继续循环,直到所有字符处理完毕;
按照这个思路,我编写了下面的代码:stringinputtbxInput。Text;doubleresult0;stringtemp;charlastoperator;foreach(charcininput)循环遍历每个字符{if(char。IsDigit(c))如果是数字{tempc;}else{if(!string。IsNullOrEmpty(temp))如果不是空字符{switch(lastoperator){case:resultint。Parse(temp);break;case:resultint。Parse(temp);break;}}lastoperatorc;temp;}}if(!string。IsNullOrEmpty(temp)){switch(lastoperator){case:resultint。Parse(temp);break;case:resultint。Parse(temp);break;}}
逻辑倒是挺简单,之前没遇到过的函数我加了注释,应该不难理解。
运行效果:
细心的学员可能注意到,上面的代码中switch部分是一样的。对于代码相同或者是功能相似的部分,我们就提倡用函数进行封装,这样以后再使用的时候,直接调用这个函数就好了。比如,我们把上面用于计算的代码封装成下面的函数:doublecalcnormal(doubleresult,charop,stringtemp){if(!string。IsNullOrEmpty(temp))如果不是空字符{switch(op){case:resultint。Parse(temp);break;case:resultint。Parse(temp);break;}}returnresult;}
函数的声明:doublecalcnormal(doubleresult,charop,stringtemp)返回类型函数名变量类型及变量名
这样在程序中,我们直接调用函数名的方式就好了。优化后的代码:stringinputtbxInput。Text;doubleresult0;stringtemp;charlastoperator;foreach(charcininput)循环遍历每个字符{if(char。IsDigit(c))如果是数字{tempc;}else{resultcalcnormal(result,lastoperator,temp);lastoperatorc;temp;}}resultcalcnormal(result,lastoperator,temp);
代码精简了不少,看起来也很清晰。实际执行结果,跟之前一样。
函数,可以说是编程中的重中之重。我们经常听说很多经验丰富的老程序员,开发效率胜过十个新手,就是因为老程序员积累了丰富的类库,里面涵盖了各种各样的函数,这些函数都是经历过几年甚至十几年千万次的调用,通过无数次修改与Bug修复千锤百炼过的。想要什么功能就是一堆函数的组合,效率当然高了。拿我来说,我用C开发了10多年,从一开始就慢慢建设并丰富自己的开发库,以前我开发出一个产品,可能需要12年的时间才能成型。现在,基于类库,开发出类似的产品,可能只需要2个月。当然类库的磨练也不是一蹴而就的,我现在的类库,至少经历了3次架构级别的调整。有点扯远了,归根结底一句话,编程也要学会积累。
回到我们的功能。虽然有了一些进展,能够实现了连加连减,但是乘法和除法我们并没有涉及到,并且还有更复杂的,比如括号嵌套,这种:(12(222))222
加减乘除外加括号嵌套,常规的字符串处理复杂度太高了。想要完美解决,可能相当于要做一个小型的编译器了。
那要如何来解决呢?我们下节继续。