ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

四则运算计算机C++项目练习

2022-03-02 21:35:23  阅读:151  来源: 互联网

标签:练习 err int expr 四则运算 len char C++ txt


#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <math.h>
#include "mystack.h"
#include "myqueue.h"

#define DEBUG               0
#define MAX_LENGTH_TXT      500

typedef enum {
    ERR_NONE = 0,
    ERR_IO,
    ERR_STACK,
    ERR_QUEUE
} errNum;

typedef struct {
    errNum error;
    int line;
} myError;

int getExpr(char expr[]);
myError processQueue(char expr[], int len_txt);
double calcQueue();
char* zeroRid(double num);

int main() {
    char expr[MAX_LENGTH_TXT];
    int len_txt = 0;
    myError err;
    double res;

    while (1) {
        stackClean();
        queueClean();
        printf("please input a expression (Supported operators '+ - * / ( )' and Bracket nesting) or 'q' to exit\n> ");
        len_txt = getExpr(expr);                // 获取输入
        if (len_txt == -1) {
            break;
        } else if (len_txt == 0) {
            continue;
        }
#if (DEBUG == 1)
        printf("> %s | Length: %d\n", expr, len_txt);
#endif
        err = processQueue(expr, len_txt);      // 处理表达式
        if (err.error == ERR_IO) {
            printf("[ERROR_IO]: (Line: %d)Please check the input carefully and try again later\n", err.line);
            continue;
        } else if (err.error == ERR_QUEUE) {
            printf("[ERROR_QUEUE]: (Line: %d)Queue full, input too long please try again\n", err.line);
            continue;
        } else if (err.error == ERR_STACK) {
            printf("[ERROR_STACK]: (Line: %d)Stack full, input too long please try again\n", err.line);
            continue;
        }
#if (DEBUG == 1)
        printf("> ");
        queuePrint();
#endif
        res = calcQueue();                      // 计算结果
        printf("= %s\n", zeroRid(res));
    }

    return 0;
}

/* 获取运算符优先级 */
uint8_t priority(char symbol) {
    switch (symbol) {
        case '+':
        case '-': return 1;
        case '*':
        case '/': return 2;
        case '(': return 3;
    }
    return 0;
}

/* 从标准输入中读入一行表达式 
 * 返回读入的字符串长度
 * -1 表示输入为退出标记或栈满退出
 */
int getExpr(char expr[]) {
    char ch;
    int len_txt = 0;
    while (1) {
        ch = getchar();
        if (ch == 'q') {  // 输入q, 直接退出
            len_txt = -1;
            break;
        }
        if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '(' || ch == ')') {
            /* 输入过滤 */
            expr[len_txt++] = ch;
            if (len_txt >= MAX_LENGTH_TXT) {
                len_txt = -1;  
                break;  // 输入溢出
            }
        } else if (ch == '\n') {
            expr[len_txt] = '\0';
            break;
        }
    }
    return len_txt;
}

/* 处理中序表达式,以逆波兰形式存入队列
 * 没有错误,返回0
 */
myError processQueue(char expr[], int len_txt) {
    int8_t  flag_sym_fr = 1;        // 标记数值正负,数值入队列后复位
    int8_t  flag_sym_bk[50] = {0},
            flag_sym_bk_cnt = 0;    // 标记左括号后缀,由右括号复位
    int8_t  flag_point = 1;         // 浮点数转换时标记位,数值入对列后复位
    char symbol;
    double value;
    myNode temp_node;
    uint8_t isok;
    myError t_err = {ERR_NONE};

    for (int i = 0; i < len_txt; ++i) {
        if (expr[i] == '+' || expr[i] == '-' || expr[i] == '*' || expr[i] == '/') {
            /* 加减乘除符号处理 */
            if (expr[i] == '+' || expr[i] == '-') {
                /* 加减号处理 */
                if (i == 0 || expr[i-1] == '+' || expr[i-1] == '-' || expr[i-1] == '*' || expr[i-1] == '/' || expr[i-1] == '(') {
                    /* 正负作为数值前缀 */
                    if (expr[i] == '-') {  // 负号处理
                        if (expr[i+1] == '(') {  // 符号后是左括号
                            flag_sym_bk[flag_sym_bk_cnt] = 1;
                        } else if ((expr[i+1] >= '0' && expr[i+1] <= '9') || expr[i+1] == '.') {  // 符号后是数字或小数点
                            flag_sym_fr = -1;
                        } else {  // 错误输入
                            t_err.error = ERR_IO;
                            t_err.line = __LINE__;
                            break;  // 错误输入处理
                        }
                    } else {  // 正号处理
                        if (!((expr[i+1] >= '0' && expr[i+1] <= '9') || expr[i+1] == '.')) {  // 符号后不是数字或小数点
                            t_err.error = ERR_IO;
                            t_err.line = __LINE__;
                            break;  // 错误输入处理
                        }
                    }
                } else {
                    /* 正负作为运算符 */
                    isok = stackTop(&symbol);  // 获取栈顶符号
                    while (isok && symbol != '(' && priority(expr[i]) <= priority(symbol)) {
                        /*
                         *  字符优先级低于栈顶符号,依次弹栈直到遇到字符优先级高于栈顶符号或者遇到左括号或者空栈
                         *  (如果和栈顶符号优先级一样栈顶符号也要先弹栈,因为优先级一样运算顺序是从左往右)
                         */
                        temp_node.type = ENUM_SYMBOL;
                        stackPop(&temp_node.value.symbol);  // 弹栈
                        isok = queuePush(temp_node);  // 入队列
                        if (!isok) {
                            t_err.error = ERR_QUEUE;
                            t_err.line = __LINE__;
                            break;  // 队列满报错
                        }
                        isok = stackTop(&symbol);  // 重新获取栈顶符号
                    }
                    if (t_err.error != ERR_NONE) break;
                    isok = stackPush(expr[i]);  // 当前符号入栈
                    if (!isok) {
                        t_err.error = ERR_STACK;
                        t_err.line = __LINE__;
                        break;  // 栈满报错
                    }
                }
            } else {
                /* 乘除号处理 */
                if ((i == 0 && queueIsEmpty()) || expr[i+1] == '*' || expr[i+1] == '/' || expr[i+1] == ')') {
                    t_err.error = ERR_IO;
                    t_err.line = __LINE__;
                    break;  // 错误输入处理
                }
                isok = stackTop(&symbol);  // 获取栈顶符号
                while (isok && symbol != '(' && priority(expr[i]) <= priority(symbol)) {
                    /*
                     *  字符优先级低于栈顶符号,依次弹栈直到遇到字符优先级高于栈顶符号或者遇到左括号或者空栈
                     *  (如果和栈顶符号优先级一样栈顶符号也要先弹栈,因为优先级一样运算顺序是从左往右)
                     */
                    temp_node.type = ENUM_SYMBOL;
                    stackPop(&temp_node.value.symbol);  // 弹栈
                    isok = queuePush(temp_node);  // 入队列
                    if (!isok) {
                        t_err.error = ERR_QUEUE;
                        t_err.line = __LINE__;
                        break;  // 队列满报错
                    }
                    isok = stackTop(&symbol);  // 重新获取栈顶符号
                }
                if (t_err.error != ERR_NONE) break;
                isok = stackPush(expr[i]);  // 当前符号入栈
                if (!isok) {
                    t_err.error = ERR_STACK;
                    t_err.line = __LINE__;
                    break;  // 栈满报错
                }
            }
        } else if (expr[i] == '(') {
            /* 左括号直接入栈 */
            if (expr[i-1] == ')') {
                expr[i-1] = '*';
                i -= 2;
                continue;
            }
            if (flag_sym_bk[flag_sym_bk_cnt] || flag_sym_bk_cnt != 0) {
                flag_sym_bk_cnt++;
            }
            isok = stackPush(expr[i]);
            if (!isok) {
                t_err.error = ERR_STACK;
                t_err.line = __LINE__;
                break;  // 栈满报错
            }
        } else if (expr[i] == ')') {
            /* 右括号,依次弹栈入队列,直到遇到左括号 */
            do {
                isok = stackPop(&symbol);
                if (!isok) {
                    t_err.error = ERR_IO;
                    t_err.line = __LINE__;
                    break;  // 错误输入处理
                }
                if (symbol != '(') {
                    temp_node.type = ENUM_SYMBOL;
                    temp_node.value.symbol = symbol;
                    isok = queuePush(temp_node);  // 入队列
                    if (!isok) {
                        t_err.error = ERR_QUEUE;
                        t_err.line = __LINE__;
                        break;  // 队列满报错
                    }
                }
            } while (symbol != '(');
            if (t_err.error != ERR_NONE) break;
            /* 处理并复位标记 flag_sym_bk */
            if (flag_sym_bk_cnt && flag_sym_bk[--flag_sym_bk_cnt]) {
                temp_node.type = ENUM_SYMBOL;
                temp_node.value.symbol = '#';
                isok = queuePush(temp_node);  // 入队列
                if (!isok) {
                    t_err.error = ERR_QUEUE;
                    t_err.line = __LINE__;
                    break;  // 队列满报错
                }
                flag_sym_bk[flag_sym_bk_cnt] = 0;
            }
        } else {
            /* 读取数字并入队列 */
            if (i > 0 && expr[i-1] == ')') {
                expr[i-1] = '*';  // 数值前为右括号则用乘号填充
                i -= 2;
                continue;
            }
            value = 0.0;
            while ((expr[i+1] >= '0' && expr[i+1] <= '9') || expr[i+1] == '.') {
                if (expr[i] == '.') {
                    if (flag_point == 1) {
                        flag_point = -1;
                    } else {
                        t_err.error = ERR_IO;
                        t_err.line = __LINE__;
                        break;  // 错误输入处理
                    }
                } else {
                    if (flag_point == 1) {
                        value = value * 10 + (expr[i] - '0');
                    } else {
                        value = value + pow(10, flag_point--) * (expr[i] - '0');
                    }
                }
                ++i;
            }
            if (t_err.error != ERR_NONE) break;
            if (expr[i] == '.') {
                if (flag_point == 1) {
                    flag_point = -1;
                } else {
                    t_err.error = ERR_IO;
                    t_err.line = __LINE__;
                    break;  // 错误输入处理
                }
            } else {
                if (flag_point == 1) {
                    value = value * 10 + (expr[i] - '0');
                } else {
                    value = value + pow(10, flag_point--) * (expr[i] - '0');
                }
            }
            temp_node.type = ENUM_NUMBER;
            temp_node.value.number = value * flag_sym_fr;
            isok = queuePush(temp_node);  // 入队列
            if (!isok) {
                t_err.error = ERR_QUEUE;
                t_err.line = __LINE__;
                break;  // 队列满报错
            }
            /* 后续处理 */
            flag_sym_fr = 1;
            flag_point = 1;
            if (expr[i+1] == '(') {
                expr[i--] = '*';
            }
        }
    }
    if (t_err.error == ERR_NONE) {
        isok = stackPop(&symbol);
        while (isok) {
            if (symbol == '(') {
                /* 处理并复位标记 flag_sym_bk */
                if (flag_sym_bk_cnt && flag_sym_bk[--flag_sym_bk_cnt]) {
                    temp_node.type = ENUM_SYMBOL;
                    temp_node.value.symbol = '#';
                    isok = queuePush(temp_node);  // 入队列
                    if (!isok) {
                        t_err.error = ERR_QUEUE;
                        t_err.line = __LINE__;
                        break;  // 队列满报错
                    }
                    flag_sym_bk[flag_sym_bk_cnt] = 0;
                }
            } else {
                temp_node.type = ENUM_SYMBOL;
                temp_node.value.symbol = symbol;
                isok = queuePush(temp_node);  // 入队列
                if (!isok) {
                    t_err.error = ERR_QUEUE;
                    t_err.line = __LINE__;
                    break;  // 队列满报错
                }
            }
            isok = stackPop(&symbol);  // 重新获取栈顶符号
        }
    }
    return t_err;
}

double m_add(double a, double b) {
    return (a + b);
}

double m_sub(double a, double b) {
    return (a - b);
}

double m_mul(double a, double b) {
    return (a * b);
}

double m_div(double a, double b) {
    return (a / b);
}

double m_neg(double a) {
    return -a;
}

/* 根据逆波兰队列计算式值 */
double calcQueue() {
    double t_a, t_b, t_stack[MAX_LENGTH_QUEUE];
    int t_stack_cnt = 0;
    myNode t_node;
    uint8_t isok;

    isok = queuePop(&t_node);
    while (isok) {
        if (t_node.type == ENUM_NUMBER) {
            t_stack[t_stack_cnt++] = t_node.value.number;
        } else {
            switch (t_node.value.symbol) {
                case '+': {
                    t_b = t_stack[--t_stack_cnt];
                    t_a = t_stack[--t_stack_cnt];
                    t_stack[t_stack_cnt++] = m_add(t_a, t_b);
                    break;
                }
                case '-': {
                    t_b = t_stack[--t_stack_cnt];
                    t_a = t_stack[--t_stack_cnt];
                    t_stack[t_stack_cnt++] = m_sub(t_a, t_b);
                    break;
                }
                case '*': {
                    t_b = t_stack[--t_stack_cnt];
                    t_a = t_stack[--t_stack_cnt];
                    t_stack[t_stack_cnt++] = m_mul(t_a, t_b);
                    break;
                }
                case '/': {
                    t_b = t_stack[--t_stack_cnt];
                    t_a = t_stack[--t_stack_cnt];
                    t_stack[t_stack_cnt++] = m_div(t_a, t_b);
                    break;
                }
                case '#': {
                    t_a = t_stack[--t_stack_cnt];
                    t_stack[t_stack_cnt++] = m_neg(t_a);
                    break;
                }
            }
        }
        isok = queuePop(&t_node);
    }

    return t_stack[0];
}

/* 美化数值显示 */
char* zeroRid(double num) {
    static char str[200];
    char *point = str, *zero;

    sprintf(str, "%.15lf", num);
    while (*point != '.') point++;
    zero = str + 16;
    if (zero < point) {
        sprintf(str, "%g", num);
    } else {
        while (*zero == '0') zero--;
        if (*zero == '.') {
            *zero = '\0';
        } else {
            *(zero + 1) = '\0';
        }
    }
    
    return str;
}

标签:练习,err,int,expr,四则运算,len,char,C++,txt
来源: https://blog.csdn.net/MAKAers/article/details/123240568

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有