用C语言写一个计算器

本文介绍如何用C语言编写一个计算器,涵盖了加减法、乘除法、四则混合运算以及支持三角函数。通过构建计算树来处理不同运算级别的优先级,同时对程序进行了逐步优化,包括处理浮点型运算和括号运算,实现了对括号内表达式的正确计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用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×(cd)这样一个简单的功能,要求编译器可以识别出 + , × , − , ( , ) +,\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),相对来说更加简单。getchegetch是Windows独有的函数,在头文件conio.h中故不赘述。

getsscanf(%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
评论 33
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

微小冷

请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值