用C语言写一个计算器,除了四则混合运算之外,还支持三角函数和绝对值等函数。
PS E:\Code\PL\calc> .\a.exe
abs(3*5-4^2)
abs(3*5-4^2)=1.000000
25-7+6*(4-5)
25-7+6*(4-5)=12.000000
在计算器中,至少包含两类变量,即数字和运算符。例如,如果希望实现 a + b × ( c − d ) a+b\times (c-d) a+b×(c−d)这样一个简单的功能,要求编译器可以识别出 + , × , − , ( , ) +,\times,-,(,) +,×,−,(,)这五个符号,并理清彼此的计算顺序,最后生成一棵语法树,然后实现输出。
1. 加减法运算
万事开头难,所以我们选择一个简单到无脑的开头。首先,我们考虑实现 a + b a+b a+b这样简单的两数运算,即如下所示,十分简单且无脑。
void douCalc(){
while (1){
double i, j, s;
char k;
scanf("%lf%c%lf", &i, &k, &j);
switch (k){
case '+':
s = i+j;
break;
case '-':
s = i-j;
break;
case '*':
s = i*j;
break;
case '/':
s = i/j;
break;
default:
break;
}
printf("%lf\n", s);
}
}
然后,我们考虑,如何实现一个连加器,旨在解决 a + b + c + . . . a+b+c+... a+b+c+...的计算问题。这里虽然不涉及到运算次序,但仍旧需要处理多个不确定个数的变量,所以我们不再可以直接用类似scanf("%lf%c%lf", &i, &k, &j);
的方案来实现数据的输入,而必须建立一个链表来存储变量。
C语言输入输出
在C语言中,可以通过至少三种方式来读取键盘输入的值:
scanf()
:和 printf() 类似,scanf() 可以输入多种类型的数据。getchar()
、getche()
、getch()
:这三个函数都用于输入单个字符。gets()
:获取一行数据,并作为字符串处理。
其中,scanf
是格式化扫描的意思,可以通过格式控制符对输入字符进行格式化,并赋值给相关变量。
格式控制符 | 说明 |
---|---|
%c | 读取单一字符 |
%s | 读取一个字符串(以空白符为结束) |
%f、%lf | 读取十进制形式小数,赋值给float、double 类型 |
%e、%le | 读取指数形式小数,赋值给 float、double 类型 |
%g、%lg | 读取十进制或指数形式的小数, 并分别赋值给 float、double 类型 |
- 整数格式化
||short|int|long|
|-|-|-|-|-|
|十进制|%hd|%d|%ld
|八进制|%ho|%o|%lo
|十六进制|%hx|%x|%lx|
|无符号|%hu|%u|%lu|
getchar()
等价于scanf("%c", c)
,相对来说更加简单。getche
和getch
是Windows独有的函数,在头文件conio.h
中故不赘述。
gets
和scanf(%s,s)
的区别在于,后者在使用的过程中会把空格当作终止符,而前者不会。
所以,我们在实现连加的过程中,会使用gets
作为交互方法。
由于我们实现的是一个连加器,所以输入字符中只包含数字和加号,那么接下来,我们需要遍历输入字符,通过加号来将数字分开。我们可以很方便地写下一个简单而丑陋的小程序。
void adds(){
char str[100];
char numStr[20];
int num[20];
int val;
int i,j,k;
while (1){
gets(str);
i = 0;j = 0;k = 0;
while (str[i]!='\0'){
if (str[i]=='+'){
num[k] = atoi(numStr);
k++;
j = 0;
}else{
numStr[j] = str[i];
j++;
}
i++;
}
num[k]=atoi(numStr);
val = 0;
for (int i = 0; i < k+1; i++){
val += num[i];
}
printf("%d\n",val);
}
}
int main(){
adds();
return 0;
}
由于加减法具有相同的运算优先级,在实现上不过是为后续的数字加上一个负号而已,故可十分方便地在原有程序上修改。
此外,adds
代码乍看上去没什么问题,但str
的值在更新之前,并不会自动清零,由此带来的bug需要创建一个字符串清零的函数。修改之后的代码如下
#include <stdio.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
void strClear(char *str,int n){
for (int i = 0; i < n; i++){
str[i]=NULL;
}
}
void adds(){
char str[100];
char numStr[20];
int num[20];
int val;
int i,j,k;
while (1){
gets(str);
i = 0;j = 0;k = 0;
while (str[i]!='\0'){
if (str[i]=='+'){
num[k] = atoi(numStr);
strClear(numStr,20);
k++;
j = 0;
}else if (str[i]=='-'){
num[k] = atoi(numStr);
strClear(numStr,20);
k++;
numStr[0] = str[i];
j = 1;
}else{
numStr[j] = str[i];
j++;
}
i++;
}
num[k]=atoi(numStr);
strClear(numStr