模拟计算器实训项目总结

写在前面

2020/07/17~2020/09/07是暑假期间,2020/08/24 ~ 2020/08/29学校组织了线上实训,2020/09/12是线下实训的辅导与答辩,我们组选择的是模拟计算器。其实当初选择这个的原因的因为我以前写过这个项目类似的OJ的例题:HNUCM-OJ1232算法3-4表达式求值,中缀转后缀表达式求值
想知道更多关于这个项目的知识可以去这个博客看一下。

在这里插入图片描述

项目代码:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
//  宏定义数组的最大长度
#define cmax 100010
//  定义浮点数的绝对误差
const double AbsErr = 1e-6;
//  定义储存中间及最后的运算结果的结构体StackNum
typedef struct
{
    double data[cmax];
    int top;
} StackNum;
//  定义储存中间及最后的运算结果的栈s1
StackNum s1;
//  定义存储运算符的结构体StackOperation
typedef struct
{
    char data[cmax];
    int top;
} StackOperation;
//  定义存储运算符的栈s2
StackOperation s2;
//  定义运算符的优先级的字符数组priority
//  通过二维数组判断运算符的优先级
//  其中'0'表示该种关系不会存在
char priority[20][20] =
{
    {'>', '>', '>', '>', '>', '>', '>', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'!'
    {'<', '>', '>', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'+'
    {'<', '>', '>', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'-'
    {'<', '>', '>', '>', '>', '<', '>', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'*'
    {'<', '>', '>', '>', '>', '<', '>', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'/'
    {'<', '>', '>', '>', '>', '>', '>', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'^'
    {'<', '>', '>', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'%'
    {'<', '<', '<', '<', '<', '<', '<', '<', '=', '<', '<', '<', '<', '<', '<', '<', '<', '0'}, //'('
    {'>', '>', '>', '>', '>', '>', '>', '0', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //')'
    {'<', '<', '<', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'>'
    {'<', '<', '<', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'<'
    {'<', '<', '<', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'>='  //  用'X'表示
    {'<', '<', '<', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'<='  //  用'Y'表示
    {'<', '<', '<', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'=='  //  用'Z'表示
    {'<', '<', '<', '<', '<', '<', '<', '<', '>', '>', '>', '>', '>', '>', '>', '>', '>', '>'}, //'!='  //  用'W'表示
    {'<', '<', '<', '<', '<', '<', '<', '<', '>', '<', '<', '<', '<', '<', '<', '>', '>', '>'}, //'&&'  //  用'&'表示
    {'<', '<', '<', '<', '<', '<', '<', '<', '>', '<', '<', '<', '<', '<', '<', '>', '>', '>'}, //'||'  //  用'|'表示
    {'<', '<', '<', '<', '<', '<', '<', '<', '0', '<', '<', '<', '<', '<', '<', '<', '<', '='}, //'#'
};
//  getIndex用于获取每一个运算符在priority数组里面的下标
int getIndex(char c)
{
    int index;
    switch (c)
    {
    case '!':
        index = 0;
        break;
    case '+':
        index = 1;
        break;
    case '-':
        index = 2;
        break;
    case '*':
        index = 3;
        break;
    case '/':
        index = 4;
        break;
    case '^':
        index = 5;
        break;
    case '%':
        index = 6;
        break;
    case '(':
        index = 7;
        break;
    case ')':
        index = 8;
        break;
    case '>':
        index = 9;
        break;
    case '<':
        index = 10;
        break;
    case 'X':
        index = 11;
        break;
    case 'Y':
        index = 12;
        break;
    case 'Z':
        index = 13;
        break;
    case 'W':
        index = 14;
        break;
    case '&':
        index = 15;
        break;
    case '|':
        index = 16;
        break;
    case '#':
        index = 17;
        break;
    }
    return index;
}
//  getPriority用于获取栈顶元素与即将入栈的元素的优先级
char getPriority(char a, char b)
{
    int index1 = getIndex(a);
    int index2 = getIndex(b);
    return priority[index1][index2];
}
//  calculate直接计算中间表达式结果
double calculate(double num1, char c, double num2)
{
    double Num;
    switch (c)
    {
    case '+':
        Num = num2 + num1;
        break;
    case '-':
        Num = num2 - num1;
        break;
    case '*':
        Num = num2 * num1;
        break;
    case '/':
        Num = num2 / num1;
        break;
    case '^':
        Num = pow(num2, num1);
        break;
    case '%':
        Num = fmod(num2, num1);
        break;
    case '>':
    {
        if (num2 > num1 + AbsErr)
            Num = 1;
        else
            Num = 0;
    }
    case '<':
    {
        if (num2 < (num1 + AbsErr))
            Num = 1;
        else
        {
            Num = 0;
        }
    }
    case 'X':
    {
        if (num2 >= (num1 + AbsErr))
            Num = 1;
        else
            Num = 0;
        break;
    }
    case 'Y':
    {
        if (num2 <= (num1 - AbsErr))
            Num = 1;
        else
            Num = 0;
        break;
    }
    case 'Z':
    {
        if (fabs(num2 - num1) <= AbsErr)
            Num = 1;
        else
            Num = 0;
        break;
    }
    case 'W':
    {
        if (fabs(num2 - num1) > AbsErr)
            Num = 1;
        else
            Num = 0;
        break;
    }
    case '|':
    {
        if (num1 == 0 && num2 == 0)
            Num = 0;
        else
            Num = 1;
        break;
    }
    case '&':
    {
        if (num2 != 0 && num1 != 0)
            Num = 1;
        else
            Num = 0;
        break;
    }
    }
    return Num;
}
//  getAnswer主要函数,用于计算结果的主要函数
double getAnswer(char s[])
{
    s2.data[++s2.top] = '#'; //  初始化栈2便于运算符之间的计算
    int len = strlen(s);
    int i = 0;
    int counter = 0; //  作为数字字符是有一位还是多位的形式
    int flag = 0;    //  小数标记
    while (i < len)
    {
        if (s[i] == '.') //  优先处理小数,flag==1则是小数情况
        {
            flag = 1;
            counter = 0;
            i++;
        }
        if (s[i] >= '0' && s[i] <= '9') //  如果是数值则进栈1
        {
            if (flag == 1) //  小数情况
            {
                if (counter == 0) //  小数点后的第一位
                {
                    /*先将s1栈顶元素出栈,加上刚刚那个s[i]的小数位,再入栈*/
                    double temp = s1.data[s1.top--];
                    temp = temp + 0.1 * (s[i] - '0');
                    s1.data[++s1.top] = temp;
                    counter++;
                    i++;
                }
                else
                {
                    int m = counter + 1; //  m表示该数字s[i]为小数点后的第m位
                    /*先将s1栈顶元素出栈,加上刚刚那个s[i]的小数位,再入栈*/
                    double temp = s1.data[s1.top--];
                    temp = temp + pow(0.1, m) * (s[i] - '0');
                    s1.data[++s1.top] = temp;
                    counter++;
                    i++;
                }
            }
            else //  非小数情况
            {
                if (counter == 0) //  该数字为第一位
                {
                    s1.data[++s1.top] = s[i] - '0'; //进栈,并将字符型转化为整形
                    counter++;
                    i++;
                }
                else //  多位数进栈
                {
                    /*先将s1栈顶元素出栈并且乘以10,加上刚刚那个s[i]的数位,再入栈*/
                    double temp = s1.data[s1.top--];
                    temp = temp * 10 + (s[i] - '0');
                    s1.data[++s1.top] = temp;
                    counter++;
                    i++;
                }
            }
        }
        else
        {
            counter = 0; //  计数器归零
            flag = 0;    //  小数标记器归零
            //  比较s2.data[s2.top]和s[i]的优先级
            char ch = getPriority(s2.data[s2.top], s[i]);
            switch (ch)
            {
            //  s2.data[s2.top]优先级小于s[i]的优先级
            case '<':
            {
                //  运算符直接进栈
                s2.data[++s2.top] = s[i];
                i++;
                break;
            }
            //  s2.data[s2.top]优先级大于s[i]的优先级
            case '>':
            {
                //  当前运算符出栈
                char c = s2.data[s2.top--];
                if (c == '!') //  如果是!(即 非 逻辑符时,则只需数值栈出栈一次即可)
                {
                    //  数值栈栈顶元素出栈
                    double num1 = s1.data[s1.top--];
                    if (!num1)
                        s1.data[++s1.top] = 0;
                    else
                        s1.data[++s1.top] = 1;
                }
                else //  如果是其他符号时,数值栈连续出栈两次
                {
                    double num1 = s1.data[s1.top--];
                    double num2 = s1.data[s1.top--];
                    //  计算新的值入栈
                    double MidNum = calculate(num1, c, num2);
                    s1.data[++s1.top] = MidNum;
                }
                break;
            }
            case '=':
            {
                s2.top--;
                i++;
                break;
            }
            }
        }
    }
    return s1.data[s1.top];
}
int main()
{
    char s[cmax];
    memset(s, '\0', sizeof(s));
    printf("*-----------------该程序可以实现基本表达式的计算-----------------*\n\n");
    printf("*----------------------------------------------------------------*\n");
    printf("*                    请输入你想要进行的操作                      *\n");
    printf("*                                                                *\n");
    printf("*                    1.算术表达式计算                            *\n");
    printf("*                                                                *\n");
    printf("*                    2.关系表达式计算                            *\n");
    printf("*                                                                *\n");
    printf("*                    3.逻辑表达式计算                            *\n");
    printf("*                                                                *\n");
    printf("*                    0.退出该程序                                *\n");
    printf("*                                                                *\n");
    printf("*----------------------------------------------------------------*\n");
    printf("\n");
    int n;
    while (~scanf("%d", &n))
    {
        switch (n)
        {
        case 1:
        {
            printf("请输入算术表达式(以'#'表示结束):\n");
            scanf("%s", s);
            if(s[strlen(s)-1]!='#')
            {
                printf("请输入以‘#’结尾的表达式!\n");
                printf("*----------------------------请继续操作--------------------------*\n\n");
                break;
            }
            s1.top = -1;
            s2.top = -1;
            double num; //最终结果
            num = getAnswer(s);
            printf("该算术表达式结果为:\n%.3lf\n", num);
            printf("*----------------------------请继续操作--------------------------*\n");
            printf("\n");
            break;
        }
        case 2:
        {
            printf("请输入关系表达式(其中 >= 用X表示, <= 用Y表示, == 用Z表示, != 用W表示,以'#'表示结束):\n");
            scanf("%s", s);
            if(s[strlen(s)-1]!='#')
            {
                printf("请输入以‘#’结尾的表达式!\n");
                printf("*----------------------------请继续操作--------------------------*\n\n");
                break;
            }
            double num = getAnswer(s);
            int flag = (int)num;
            if (flag == 1)
            {
                printf("该关系表达式结果为:\nTURE\n");
            }
            else
            {
                printf("该关系表达式结果为:\nFALSE\n");
            }
            printf("*----------------------------请继续操作--------------------------*\n");
            printf("\n");
            break;
        }
        case 3:
        {
            printf("请输入逻辑表达式( && 用'&'表示, || 用'|'表示,以'#'表示结束):\n");
            scanf("%s", s);
            if(s[strlen(s)-1]!='#')
            {
                printf("请输入以‘#’结尾的表达式!\n");
                printf("*----------------------------请继续操作--------------------------*\n\n");
                break;
            }
            double num = getAnswer(s);
            int flag = (int)num;
            if (flag == 1)
            {
                printf("该逻辑表达式结果为:\nTRUE\n");
            }
            else
                printf("该逻辑表达式结果为:\nFALSE\n");

            printf("*----------------------------请继续操作--------------------------*\n");
            printf("\n");
            break;
        }
        case 0:
        {
            printf("*----------------------------------------------------------------*\n");
            printf("*                                                                *\n");
            printf("*                      程序结束,谢谢使用!                       *\n");
            printf("*                                                                *\n");
            printf("*----------------------------------------------------------------*\n");

            return 0;
        }
        }
    }
    return 0;
}

运行结果展示:

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Liknana

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值