C语言:(新)四则计算器(支持括号和次方运算连续输入计算)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YangZuo_Chester/article/details/78359245

之前已经写过一个计算器,每次回顾都觉得很复杂,一直在考虑重新写一个
支持小数运算
存储数据改为了double类型
支持整数次方
运算中乘法可以用x或者*表示,两个都支持
平台visual studio 2015
另外:输入的时候输入法最好是英文状态

这次的存储模式如下:
这里写图片描述

大概说一下计算流程:
1:将输入的文本提取出运算符,数字,次方和等级四类
2:每次运算找到当前的最高等级,先计算次方,再计算四则运算
3:计算结果覆盖至第二个aNum结构体的data,并废弃第一个结构体
4:2、3循环

输入的公式拆分成data,oper(operator)和class三类 data:即为公式中的每个数字 oper:+-*/运算符
class:符号的运算等级(类似于优先级)

讲一下我构造class的这个思路:
在括号外的公式中,+-的运算等级(class)为1,*/的运算等级为2
在括号内的公式中,+-对应等级为3(大于括号外的/等级),而/的等级为4

在这次的计算中,我把计算单独拿了出来
函数:float compute(float num1, float num2, char opt)
一次只运算一对数字,而每对计算的先后顺序就根据class等级值

每一个struct aNum用了链表来连接,利于计算后的数据处理

例:

3+5x(2+1)-7
第一次运算时,找到最高的class,即存储“data=2,oper=’+’,class=3”的struct,2+1=3,而当前struct就不能再留下了,此时就把结果3覆盖到下一个struct的data上,然后抛弃当前存储“data=2”的struct,即p_front->next=p->next;每次计算如此循环

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define INIT_STRING_SIZE 100
#define True 1
#define False 0
int saved_class[4] = { 0, 0, 0, 0 };
typedef struct aNum {
    double data;
    char oper;
    int dataClass;
    int power;
    struct aNum *next;
}num;
typedef struct {
    char *formula;
    int length;
}string;

void setNULL(char *num)//清空一个字符串
{
    int i = 0;
    while (i<5)
    {
        num[i] = NULL;
        ++i;
    }
}
int countOperators(string *input, int &counter)//processing step 1
{//计算运算符个数
    int i = 0;
    while (input->formula[i] != '\0')
    {
        switch (input->formula[i++])
        {
        case '+':
        case '-':
        case '*':
        case '/':++counter; break;
        default:break;
        }
        ++input->length;
    }
    return 1;
}
int getData(string *input, num *nums)//processing step 2
{//把数字,符号和class存入nums的结构体
    int i = 0;    //counter of input->formula
    int k = 0;  //counter of temp;
    int power = 0;
    char temp[5];
    int inBracket = False;
    num *p = nums;
    num *body;

    while (i <= input->length)
    {
        if ((input->formula[i]<'0' || input->formula[i]>'9')&&input->formula[i]!='.'&&input->formula[i]!='^')
        {//进入此处时数据已经收集完毕
            if (input->formula[i] == '(')
            {
                inBracket = True;
                ++i;
                continue;
            }
            if (input->formula[i] == ')')
            {
                inBracket = False;
                ++i;
                continue;
            }
            body = (num *)calloc(1, sizeof(num));

            body->data = atof(temp);    //得到数字
            setNULL(temp);              //归零temp
            k = 0;

            switch (input->formula[i])
            {
            case '+':body->dataClass = inBracket == False ? 1 : 3;  //计算当前运算符的等级
                ++saved_class[body->dataClass - 1];                 //在等级数组里记录一次
                body->oper = input->formula[i];                     //得到运算符
                break;

            case '-':body->dataClass = inBracket == False ? 1 : 3;
                ++saved_class[body->dataClass - 1];
                body->oper = input->formula[i];
                break;

            case 'x':
            case '*':body->dataClass = inBracket == False ? 2 : 4;
                ++saved_class[body->dataClass - 1];
                body->oper = input->formula[i];
                break;

            case '/':body->dataClass = inBracket == False ? 2 : 4;
                ++saved_class[body->dataClass - 1];
                body->oper = input->formula[i];
                break;

            default:break;
            }
            if (power != 0)
            {
                body->power = power;
                power = 0;
            }
            p->next = body;
            p = p->next;
        }
        else if (input->formula[i] == '^')
        {
            power = input->formula[++i] - 48;
        }
        else
        {
            temp[k++] = input->formula[i];
        }
        ++i;
    }
    return 1;
}
double compute(double num1, double num2, char opt)
{//每次运算单独提取
    double result;
    switch (opt)
    {
    case '-':result = num1 - num2; break;
    case '+':result = num1 + num2; break;
    case 'x':
    case '*':result = num1 * num2; break;
    case '/':result = num1 / num2; break;
    }
    return result;
}
int processingData(num *nums)//processing step 3
{//nums作为头结点是没有数据的
    int s = 3;//saved_class
    int i = 0;
    num *p = nums;
    num *p_front;
    while (saved_class[s] == 0&&s>0)
        --s;
    while (p->next->next != NULL)//class oper next 都可以
    {
        if (p->next->dataClass != s + 1)
        {
            p = p->next;
            continue;
        }
        p_front = p;
        p = p->next;//p此时指向待计算的第一个struct aNUm
        if(p->power != 0)
        {
            p->data = pow(p->data, p->power);
            p->power = 0;
        }
        if (p->next->power != 0)
        {
            p->next->data = pow(p->next->data, p->next->power);
            p->next->power = 0;
        }
        p->next->data = compute(p->data, p->next->data, p->oper);

        p_front->next = p->next;
        free(p);
        --saved_class[s];
        while (saved_class[s] == 0&&s!=0)
            --s;
        p = nums;


    }
    if (nums->next->power != 0)//处理单个数字输入的情况,比如2^2
    {
        nums->next->data = pow(nums->next->data, nums->next->power);
    }


    printf("result=%lf", nums->next->data);
    return 1;
}
int main()
{
    int counter = 0;
    num *nums = NULL;
    string *input;
    input = (string *)calloc(1, sizeof(string));
    input->formula = (char *)calloc(INIT_STRING_SIZE, sizeof(string));


    puts("Input formula:");
    scanf("%s", input->formula);

    //得到运算符和运算符个数
    countOperators(input, counter);
    //根据运算符个数申请存储数字的空间
    nums = (num *)calloc(1, sizeof(num));
    //存储数字和运算符
    getData(input, nums);
    processingData(nums);

    free(input->formula);
    free(input);
    free(nums->next);
    free(nums);
    system("pause");
    return 0;
}

测试数据不多,有错误欢迎指出^^

猜你喜欢

转载自blog.csdn.net/YangZuo_Chester/article/details/78359245