2301_82165884 2024-11-03 01:36 采纳率: 0%
浏览 10

用C语言编写计算器代码到底是哪里错了😭


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
// 定义栈的最大容量为100
#define MAX 100

// 操作数栈结构体定义
typedef struct {
    int a[MAX];
    int* base;
    int* top;
    int stacksize;
} OPND;

// 运算符栈结构体定义
typedef struct {
    char a[MAX];
    char* base;
    char* top;
    int stacksize;
    int no;
} OPTR;

// 根据运算符返回其索引,用于后续的比较操作
int Index(char a) {
    int index = 0;
    // 根据不同的运算符设置对应的索引值
    switch (a) {
    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;
    }
    return index;
}

// 比较两个运算符的优先级
int Compare(char a, char b) {
    // 定义一个二维数组表示运算符优先级关系
    int list[7][7] = { {1,1,-1,-1,-1,1,1},
                       {1,1,-1,-1,-1,1,1},
                       {1,1,1,1,-1,1,1},
                       {1,1,1,1,-1,1,1},
                       {-1,-1,-1,-1,-1,0,2},
                       {1,1,1,1,2,1,1},
                       {-1,-1,-1,-1,-1,2,0} };
    int index1, index2;
    // 获取两个运算符的索引
    index1 = Index(a);
    index2 = Index(b);
    return list[index1][index2];
}

// 将操作数压入操作数栈
void Inopnd(int a, OPND* opnd) {
    // 将操作数存入栈顶位置
    *opnd->top = a;
    // 栈顶指针上移一位
    opnd->top++;
}

// 将运算符压入运算符栈
void Inoptr(char a, OPTR* optr) {
    // 将运算符存入栈顶位置
    *optr->top = a;
    // 栈顶指针上移一位
    optr->top++;
}

// 从操作数栈弹出操作数
int Outopnd(OPND* opnd) {
    int a;
    // 栈顶指针下移一位
    opnd->top--;
    // 获取栈顶元素
    a = *opnd->top;
    return a;
}

// 从运算符栈弹出运算符
char Outoptr(OPTR* optr) {
    char a;
    // 栈顶指针下移一位
    optr->top--;
    // 获取栈顶元素
    a = *optr->top;
    return a;
}

// 根据运算符执行相应的算术运算
int Operation(int a, int b, char c) {
    int num = 0;
    // 根据不同的运算符进行相应的计算
    switch (c) {
    case '+':
        num = a + b; break;
    case '-':
        num = a - b; break;
    case '*':
        num = a * b; break;
    case '/':
        num = a / b; break;
    }
    return num;
}

int main() {
    OPND opnd;
    OPTR optr;
    char arr[MAX];
    // 设置操作数栈的大小为MAX
    opnd.stacksize = MAX;
    // 设置运算符栈的大小为MAX
    optr.stacksize = MAX;
    // 操作数栈的基地址和初始栈顶地址指向数组a
    opnd.base = opnd.a;
    opnd.top = opnd.a;
    // 运算符栈的基地址和初始栈顶地址指向数组a
    optr.base = optr.a;
    optr.top = optr.a;
    // 将初始运算符'#'放入运算符栈
    optr.a[0] = '#';
    optr.top++;
    // 读取输入的表达式字符串
    scanf("%s", arr);
    int i = 0, j = 0;
    char c, d[100];
    int a, b, num;
    // 遍历输入的表达式字符串,直到遇到'='
    while (arr[i]!= '=') {
        // 如果当前字符不是数字
        if (isdigit(arr[i]) == 0) {
            // 如果当前运算符优先级低于栈顶运算符
            if (Compare(*optr.top, arr[i]) == -1) {
                // 将当前运算符压入运算符栈
                Inoptr(arr[i], &optr);
                i++;
            }
            // 如果当前运算符与栈顶运算符优先级相同
            else if (Compare(*optr.top, arr[i]) == 0) {
                // 弹出栈顶运算符
                c = Outoptr(&optr);
            }
            else {
                // 弹出两个操作数和一个运算符进行计算,然后将结果压入操作数栈
                a = Outopnd(&opnd);
                b = Outopnd(&opnd);
                c = Outoptr(&optr);
                num = Operation(a, b, c);
                Inopnd(num, &opnd);
            }
            i++;
        }
        else {
            // 如果当前字符是数字,将其存入临时数组d
            d[j] = arr[i];
            j++;
            // 如果下一个字符不是数字
            if (isdigit(arr[i + 1]) == 0) {
                // 在临时数组末尾添加字符串结束符
                d[j] = '\0';
                // 将临时数组中的数字字符串转换为整数并压入操作数栈
                num = atoi(d);
                Inopnd(num, &opnd);
                j = 0;
            }
            i++;
        }
    }
    printf("%d",opnd.a[2]);
    // 处理剩余的运算符和操作数,直到运算符栈顶为'#'
    while (*optr.top!= '#') {
        a = Outopnd(&opnd);
        b = Outopnd(&opnd);
        c = Outoptr(&optr);
        num = Operation(a, b, c);
        Inopnd(num, &opnd);
    }
    // 操作数栈顶指针下移一位
    opnd.top--;
    // 输出操作数栈顶元素
    printf("%d", *opnd.top);
    return 0;
}

  • 写回答

1条回答 默认 最新

  • 程风破 Java领域新星创作者 2024-11-03 11:22
    关注

    本答案参考 多次询问 ChatGPT-3.5 后选择的最佳回答,若是满意,还请采纳,谢谢

    1. 初始化问题

      • main函数中,当将初始运算符'#'放入运算符栈时,代码optr.a[0] = '#'后应该更新optr.top指向正确的栈顶位置,即optr.top = optr.a+1;。目前的代码虽然optr.top在定义结构体时已经有了初始值指向optr.a,但是直接对optr.a[0]赋值后没有正确更新top指针,可能导致后续操作出错。
    2. 逻辑问题 - 运算符处理

      • while (arr[i]!='=')循环中的运算符处理部分:
        • Compare(*optr.top, arr[i])== - 1时,只是将当前运算符压入运算符栈然后i++,但是没有考虑如果下一个字符是数字的情况,可能会导致数字的处理逻辑混乱。
        • Compare(*optr.top, arr[i])==0时,只是弹出栈顶运算符,没有对这个运算符做任何处理,这里应该根据具体情况,比如如果是括号的匹配情况,可能不需要做进一步的操作,但是对于其他运算符可能需要进行计算操作。
    3. 逻辑问题 - 操作数处理

      • else分支(处理数字的部分)中,当构建数字字符串d时,没有考虑数字可能是多位的情况。例如,如果输入123,目前的代码只会将1转换为整数压入栈,而不是整个123
    4. 输出问题

      • 在代码最后的输出部分,printf("%d",opnd.a[2]);这里直接输出opnd.a[2]是不合理的,因为在整个计算过程中,结果应该在操作数栈的栈顶(由opnd.top指向),而不是固定的opnd.a[2]。并且在处理完剩余的运算符和操作数后,已经将操作数栈顶指针下移了一位,再输出*opnd.top可能得到错误的结果。应该直接输出*opnd.top而不需要前面单独输出opnd.a[2]这一步。
    5. 栈空判断问题

      • 在从操作数栈和运算符栈弹出元素的函数OutopndOutoptr中,没有对栈空情况进行判断。如果栈已经为空还进行弹出操作会导致未定义行为。
    6. 除法运算问题

      • Operation函数中的除法运算num = a / b;没有考虑除数为0的情况,这会导致程序崩溃。
    7. 内存管理问题(虽然在这个简单示例中不明显)

      • 结构体OPNDOPTR中的base指针没有被充分利用,并且在定义结构体时可以直接初始化一些成员变量,使代码更加清晰。例如,可以在定义OPND结构体时直接初始化stacksize等成员变量。
    8. 代码风格和可读性

      • 代码中的变量命名可以更加有意义,例如d这个临时数组可以使用更有意义的名字,如num_str

    以下是部分修正后的代码示例:

    #define _CRT_SECURE_NO_WARNINGS
    #include <stdio.h>
    #include <ctype.h>
    #include <stdlib.h>
    // 定义栈的最大容量为100
    #define MAX 100
    
    // 操作数栈结构体定义
    typedef struct {
        int a[MAX];
        int* base;
        int* top;
        int stacksize;
    } OPND;
    
    // 运算符栈结构体定义
    typedef struct {
        char a[MAX];
        char* base;
        char* top;
        int stacksize;
        int no;
    } OPTR;
    
    // 根据运算符返回其索引,用于后续的比较操作
    int Index(char a) {
        int index = 0;
        // 根据不同的运算符设置对应的索引值
        switch (a) {
        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;
        }
        return index;
    }
    
    // 比较两个运算符的优先级
    int Compare(char a, char b) {
        // 定义一个二维数组表示运算符优先级关系
        int list[7][7] = { {1,1,-1,-1,-1,1,1},
                           {1,1,-1,-1,-1,1,1},
                           {1,1,1,1,-1,1,1},
                           {1,1,1,1,-1,1,1},
                           {-1,-1,-1,-1,-1,0,2},
                           {1,1,1,1,2,1,1},
                           {-1,-1,-1,-1,-1,2,0} };
        int index1, index2;
        // 获取两个运算符的索引
        index1 = Index(a);
        index2 = Index(b);
        return list[index1][index2];
    }
    
    // 将操作数压入操作数栈
    void Inopnd(int a, OPND* opnd) {
        // 将操作数存入栈顶位置
        *opnd->top = a;
        // 栈顶指针上移一位
        opnd->top++;
    }
    
    // 将运算符压入运算符栈
    void Inoptr(char a, OPTR* optr) {
        // 将运算符存入栈顶位置
        *optr->top = a;
        // 栈顶指针上移一位
        optr->top++;
    }
    
    // 从操作数栈弹出操作数
    int Outopnd(OPND* opnd) {
        if (opnd->top == opnd->base) {
            // 这里可以根据需求进行错误处理,比如返回一个特殊值或者直接退出程序
            printf("操作数栈空\n");
            return -1;
        }
        int a;
        // 栈顶指针下移一位
        opnd->top--;
        // 获取栈顶元素
        a = *opnd->top;
        return a;
    }
    
    // 从运算符栈弹出运算符
    char Outoptr(OPTR* optr) {
        if (optr->top == optr->base) {
            // 这里可以根据需求进行错误处理,比如返回一个特殊值或者直接退出程序
            printf("运算符栈空\n");
            return '\0';
        }
        char a;
        // 栈顶指针下移一位
        optr->top--;
        // 获取栈顶元素
        a = *optr->top;
        return a;
    }
    
    // 根据运算符执行相应的算术运算
    int Operation(int a, int b, char c) {
        int num = 0;
        // 根据不同的运算符进行相应的计算
        switch (c) {
        case '+':
            num = a + b; break;
        case '-':
            num = a - b; break;
        case '*':
            num = a * b; break;
        case '/':
            if (b == 0) {
                printf("除数不能为0\n");
                return -1;
            }
            num = a / b; break;
        }
        return num;
    }
    
    int main() {
        OPND opnd = { 0 };
        OPTR optr = { 0 };
        char arr[MAX];
        // 设置操作数栈的大小为MAX
        opnd.stacksize = MAX;
        // 设置运算符栈的大小为MAX
        optr.stacksize = MAX;
        // 操作数栈的基地址和初始栈顶地址指向数组a
        opnd.base = opnd.a;
        opnd.top = opnd.a;
        // 运算符栈的基地址和初始栈顶地址指向数组a
        optr.base = optr.a;
        optr.top = optr.a;
        // 将初始运算符'#'放入运算符栈并更新top指针
        *optr.top = '#';
        optr.top++;
        // 读取输入的表达式字符串
        scanf("%s", arr);
        int i = 0;
        char c;
        int a, b, num;
        // 用于构建数字字符串
        char num_str[MAX];
        int num_str_index = 0;
        // 遍历输入的表达式字符串,直到遇到'='
        while (arr[i]!= '=') {
            // 如果当前字符不是数字
            if (isdigit(arr[i]) == 0) {
                // 如果当前运算符优先级低于栈顶运算符
                if (Compare(*(optr.top - 1), arr[i]) == -1) {
                    // 将当前运算符压入运算符栈
                    Inoptr(arr[i], &optr);
                    i++;
                }
                // 如果当前运算符与栈顶运算符优先级相同
                else if (Compare(*(optr.top - 1), arr[i]) == 0) {
                    // 弹出栈顶运算符(这里假设是括号匹配情况,不需要进一步计算)
                    c = Outoptr(&optr);
                    i++;
                }
                else {
                    // 弹出两个操作数和一个运算符进行计算,然后将结果压入操作数栈
                    a = Outopnd(&opnd);
                    b = Outopnd(&opnd);
                    c = Outoptr(&optr);
                    num = Operation(b, a, c);
                    Inopnd(num, &opnd);
                }
            }
            else {
                // 如果当前字符是数字,将其存入临时数组num_str
                num_str[num_str_index]=arr[i];
                num_str_index++;
                // 如果下一个字符不是数字或者到达字符串末尾
                if (isdigit(arr[i + 1]) == 0 || arr[i + 1] == '\0') {
                    // 在临时数组末尾添加字符串结束符
                    num_str[num_str_index] = '\0';
                    // 将临时数组中的数字字符串转换为整数并压入操作数栈
                    num = atoi(num_str);
                    Inopnd(num, &opnd);
                    num_str_index = 0;
                }
                i++;
            }
        }
        // 处理剩余的运算符和操作数,直到运算符栈顶为'#'
        while (*(optr.top - 1)!= '#') {
            a = Outopnd(&opnd);
            b = Outopnd(&opnd);
            c = Outoptr(&optr);
            num = Operation(b, a, c);
            Inopnd(num, &opnd);
        }
        // 输出操作数栈顶元素
        printf("%d", *(opnd.top - 1));
        return 0;
    }
    

    这个修正后的代码解决了上述提到的部分问题,但仍然可以进一步优化,比如添加更多的错误处理和对输入表达式格式的严格检查等。

    评论

报告相同问题?

问题事件

  • 创建了问题 11月3日

悬赏问题

  • ¥15 zigbee终端设备入网失败
  • ¥15 金融监管系统怎么对7+4机构进行监管的
  • ¥15 硬件IIC从模式的数据发送,中断数据的接收,不能用HAL库(按照时序图)
  • ¥20 QAxWidget上显示一个word文档后,如何直接在该QAxWidget上修改和保存word文档
  • ¥15 Simulink仿真报错,请问如何解决
  • ¥20 宝塔面板无法添加Node项目,一直处于正在添加脚本页面
  • ¥50 Dkeil5 CT107D单片机的程序编写
  • ¥30 Ubuntu20.04中PVN3D复现过程交叉编译问题
  • ¥60 不懂得怎么运行下载来的代码
  • ¥15 CST导出3D模型图为什么和软件显示不一样?