RainMan�
2020-02-23 22:33
采纳率: 50%
浏览 712

如何用C语言编写简易的计算器

## # 编程环境为VC6.0 和 C-Free

图片说明

  • 写回答
  • 关注问题
  • 收藏
  • 邀请回答

2条回答 默认 最新

  • Eyre Turing 2020-02-24 13:44
    已采纳

    表达式计算建议看一下《数据结构》,先转换为逆波兰表达式,然后再计算。
    当然用字符串匹配也是可以的,但是这样复杂度会比较高,
    匹配最里面的括号有一个方法就是寻找第一个右括号,和这个右括号对应的左括号合起来就是最里面的括号。
    当然我给你一个逆波兰表达式的代码吧,可以解决你的问题,有点长,300多行:

    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <string.h>
    #define ElemItem    Item
    #define SUCCEED     1
    #define ERROR       0
    #define MAXLENGTH   20
    struct Item{
        int type;                   //0表示单目运算符,1表示双目运算符,2表示数字
        double num;             //如果是数字就保存在这里
        char oper[MAXLENGTH];   //如果是运算符就保存在这里
    }nullItem;
    typedef struct SNode{
        ElemItem data;
        SNode *next;
    }*Stack;
    struct QNode{
        ElemItem data;
        QNode *next;
    };
    struct Queue{
        QNode *front;
        QNode *rear;
    };
    void initStack(Stack *s){
        *s = NULL;
    }
    void push(Stack *s, ElemItem e){
        SNode *p = (SNode*)malloc(sizeof(SNode));
        p->data = e;
        p->next = *s;
        *s = p;
    }
    int pop(Stack *s, ElemItem *e = NULL){
        if(*s == NULL){
            return ERROR;
        }
        if(e != NULL){
            *e = (*s)->data;
        }
        SNode *p = *s;
        *s = (*s)->next;
        free(p);
        return SUCCEED;
    }
    ElemItem getSData(Stack s){
        if(s == NULL){
            return nullItem;
        }
        return s->data;
    }
    void initQueue(Queue *q){
        q->front = NULL;
        q->rear = NULL;
    }
    void in(Queue *q, ElemItem e){
        QNode* p = (QNode*)malloc(sizeof(QNode));
        p->data = e;
        p->next = NULL;
        if(q->rear != NULL){
            q->rear->next = p;
        }
        q->rear = p;
        if(q->front == NULL){
            q->front = p;
        }
    }
    int out(Queue *q, ElemItem *e){
        if(q->front == NULL){
            return ERROR;
        }
        *e = q->front->data;
        QNode *p = q->front;
        q->front = q->front->next;
        free(p);
        return SUCCEED;
    }
    ElemItem getQData(Queue q){
        if(q.front == NULL){
            return nullItem;
        }
        return q.front->data;
    }
    int getPriority(char *a){
        if(strcmp(a, "+") == 0 || strcmp(a, "-") == 0)
            return 1;
        if(strcmp(a, "*") == 0 || strcmp(a, "/") == 0)
            return 2;
        if(strcmp(a, "^") == 0)
            return 3;
        if(strcmp(a, "sin") == 0 || strcmp(a, "cos") == 0 || strcmp(a, "tan") == 0 \
        || strcmp(a, "ln") == 0 || strcmp(a, "exp") == 0 \
        || strcmp(a, "arcsin") == 0 || strcmp(a, "arccos") == 0 || strcmp(a, "arctan") == 0)
            return 4;
        return -1;
    }
    int getCombination(char *a){    //1表示左结合,0表示右结合
        if(strcmp(a, "+") == 0 || strcmp(a, "-") == 0 || strcmp(a, "*") == 0 || strcmp(a, "/") == 0 || strcmp(a, "^") == 0)
            return 1;
        if(strcmp(a, "sin") == 0 || strcmp(a, "cos") == 0 || strcmp(a, "tan") == 0 \
        || strcmp(a, "ln") == 0 || strcmp(a, "exp") == 0 \
        || strcmp(a, "arcsin") == 0 || strcmp(a, "arccos") == 0 || strcmp(a, "arctan") == 0)
            return 0;
        return -1;
    }
    int getOrder(char *a){          //0表示单目,1表示双目
        if(strcmp(a, "+") == 0 || strcmp(a, "-") == 0 || strcmp(a, "*") == 0 || strcmp(a, "/") == 0 || strcmp(a, "^") == 0)
            return 1;
        if(strcmp(a, "sin") == 0 || strcmp(a, "cos") == 0 || strcmp(a, "tan") == 0 \
        || strcmp(a, "ln") == 0 || strcmp(a, "exp") == 0 \
        || strcmp(a, "arcsin") == 0 || strcmp(a, "arccos") == 0 || strcmp(a, "arctan") == 0)
            return 0;
        return -1;
    }
    double getResult0(char *oper, double a1){
        if(strcmp(oper, "+") == 0)
            return a1;
        if(strcmp(oper, "-") == 0)
            return -a1;
        if(strcmp(oper, "sin") == 0)
            return sin(a1);
        if(strcmp(oper, "cos") == 0)
            return cos(a1);
        if(strcmp(oper, "tan") == 0)
            return tan(a1);
        if(strcmp(oper, "ln") == 0)
            return log(a1);
        if(strcmp(oper, "exp") == 0)
            return exp(a1);
        if(strcmp(oper, "arcsin") == 0)
            return asin(a1);
        if(strcmp(oper, "arccos") == 0)
            return acos(a1);
        if(strcmp(oper, "arctan") == 0)
            return atan(a1);
        return 0;
    }
    double getResult1(char *oper, double a1, double a2){
        if(strcmp(oper, "+") == 0)
            return a1+a2;
        if(strcmp(oper, "-") == 0)
            return a1-a2;
        if(strcmp(oper, "*") == 0)
            return a1*a2;
        if(strcmp(oper, "/") == 0)
            return a1/a2;
        if(strcmp(oper, "^") == 0)
            return pow(a1,a2);
        return 0;
    }
    double calculate(char *expression){
    //对表达式信息初步读取
        int length = strlen(expression);
        Queue firstExp;
        initQueue(&firstExp);
        int flag = -1;  //0表示数字,1表示运算符,2表示函数
        char tmp[MAXLENGTH] = {'\0'};
        for(int i=0; i<length; i++){
            if(expression[i] != ' '){
                if((expression[i] >= '0' && expression[i] <= '9') || expression[i] == '.'){
                    if(flag == 1 || flag == 2){
                        Item item;
                        item.type = getOrder(tmp);
                        strcpy(item.oper, tmp);
                        in(&firstExp, item);
                        flag = 0;
                        tmp[0] = '\0';
                    }
                    if(flag == -1){
                        flag = 0;
                    }
                }else{
                    if(expression[i] >= 'a' && expression[i] <= 'z'){
                        if(flag == 0){
                            Item item;
                            item.type = 2;
                            item.num = strtod(tmp, NULL);
                            in(&firstExp, item);
                            flag = 2;
                            tmp[0] = '\0';
                        }else if(flag == 1){
                            Item item;
                            item.type = getOrder(tmp);
                            strcpy(item.oper, tmp);
                            in(&firstExp, item);
                            flag = 2;
                            tmp[0] = '\0';
                        }else if(flag == 2 && getOrder(tmp) != -1){
                            Item item;
                            item.type = getOrder(tmp);
                            strcpy(item.oper, tmp);
                            in(&firstExp, item);
                            tmp[0] = '\0';
                        }
                        if(flag == -1){
                            flag = 2;
                        }
                    }else{
                        if(flag == 0){
                            Item item;
                            item.type = 2;
                            item.num = strtod(tmp, NULL);
                            in(&firstExp, item);
                            flag = 1;
                            tmp[0] = '\0';
                        }else if(flag == 2){
                            Item item;
                            item.type = getOrder(tmp);
                            strcpy(item.oper, tmp);
                            in(&firstExp, item);
                            flag = 1;
                            tmp[0] = '\0';
                        }else if(flag == 1){
                            Item item;
                            item.type = getOrder(tmp);
                            strcpy(item.oper, tmp);
                            in(&firstExp, item);
                            tmp[0] = '\0';
                        }
                        if(flag == -1){
                            flag = 1;
                        }
                    }
                }
                int l = strlen(tmp);
                if(l < MAXLENGTH-1){
                    tmp[l] = expression[i];
                    tmp[l+1] = '\0';
                }
                //printf("first runing\n");
            }
        }
        if(flag == 0){
            Item item;
            item.type = 2;
            item.num = strtod(tmp, NULL);
            in(&firstExp, item);
        }else{
            Item item;
            item.type = 1;
            strcpy(item.oper, tmp);
            in(&firstExp, item);
        }
        tmp[0] = '\0';
    
        //printf("first end\n");
        /*Item i;
        while(out(&firstExp, &i)){
            if(i.type == 2){
                printf("%lf\n", i.num);
            }else{
                printf("%s\n", i.oper);
            }
        }*/
    //生成后缀表达式
        int frontHasNum = 0;        //最开始有无数字,0表示无数字,1表示有数字,如果最开始无数字,则第一个运算符降为单目运算符
        Stack operStack;
        initStack(&operStack);
        Queue secondExp;
        initQueue(&secondExp);
        Item firstItem;
        while(out(&firstExp, &firstItem)){
            if(firstItem.type == 2){
                frontHasNum = 1;
                in(&secondExp, firstItem);
            }else{
                if(strcmp(firstItem.oper, "(") == 0){
                    frontHasNum = 0;
                    push(&operStack, firstItem);
                }else if(strcmp(firstItem.oper, ")") == 0){
                    frontHasNum = 1;
                    Item t;
                    while(strcmp(getSData(operStack).oper, "(") != 0){
                        if(!pop(&operStack, &t))
                            break;
                        in(&secondExp, t);
                        //printf("second 1 while\n");
                    }
                    pop(&operStack);
                }else{
                    Item t;
                    while((getPriority(firstItem.oper) < getPriority(getSData(operStack).oper)) \
                    || (getPriority(firstItem.oper)==getPriority(getSData(operStack).oper) && getCombination(getSData(operStack).oper)==1)){
                        if(!pop(&operStack, &t))
                            break;
                        in(&secondExp, t);
                        //printf("second 2 while\n");
                    }
                    if(frontHasNum == 0){
                        frontHasNum = 1;
                        firstItem.type = 0;
                    }
                    push(&operStack, firstItem);
                }
            }
            //printf("second runing\n");
        }
        while(pop(&operStack, &firstItem)){
            in(&secondExp, firstItem);
            //printf("second in runing\n");
        }
    
        //printf("second end\n");
        /*Item i2;
        while(out(&secondExp, &i2)){
            if(i2.type == 2){
                printf("%lf\n", i2.num);
            }else{
                printf("%s\n", i2.oper);
            }
        }*/
    //计算
        Stack startCalculate;
        initStack(&startCalculate);
        Item startItem;
        while(out(&secondExp, &startItem)){
            if(startItem.type == 2){
                push(&startCalculate, startItem);
            }else{
                if(startItem.type == 0){
                    Item a;
                    pop(&startCalculate, &a);
                    a.num = getResult0(startItem.oper, a.num);
                    push(&startCalculate, a);
                }else if(startItem.type == 1){
                    Item a1,a2;
                    pop(&startCalculate, &a2);
                    pop(&startCalculate, &a1);
                    Item a;
                    a.type = 2;
                    a.num = getResult1(startItem.oper, a1.num, a2.num);
                    push(&startCalculate, a);
                }
            }
            //printf("calculating\n");
        }
    
        Item result;
        pop(&startCalculate, &result);
        return result.num;
    }
    int main(int argc, char *argv[]){
        char exp[200] = {'\0'};
        if(argc != 2){
            printf("输入表达式:\n");
            //scanf("%s", exp);
            gets(exp);
        }else{
            strcpy(exp, argv[1]);
        }
        printf("计算结果为:%lf\n", calculate(exp));
        return 0;
    }
    

    运行后直接输入算式就可以了。

    打赏 评论
  • cshgiser 2020-02-24 09:26

    输入的看作一个字符串,解析这个字符串就行了,难点可能是去括号,可以用递归的方法去括号:
    以3*4/(2+1)+5^2为例
    先在外面加个括号:(3*4/(2+1)+5^2)
    遍历寻找最里面括号(2+1)
    计算(2+1)
    得出的结果替换(2+1): (3*4/3+5^2)
    再寻找最里面括号:(3*4/3+5^2)
    替换结果:29
    递归函数退出条件:只有一个数字
    至于括号里面怎么算就是解析出来表达式按计算优先级进行计算了

    打赏 评论

相关推荐 更多相似问题