为何我的C语言表达式求值代码仅输出最后一位而非计算结果?
问题分析与修复
问题根源
你的代码实现的是**后缀表达式(逆波兰表达式)**的求值逻辑,但如果输入的是普通中缀表达式(比如3+5),会直接触发错误逻辑:遇到运算符时栈中元素不足2个,弹出无效值后计算结果异常,最终仅输出表达式最后一位数字。此外代码还存在以下缺陷:
- 遇到非数字字符就强制执行运算,无边界检查
- 仅支持
+、-两种运算符 - 未处理栈溢出/下溢、除零等异常情况
- 未释放栈内存,存在内存泄漏
修复方案
根据需求场景提供两种修复代码:
场景1:正确处理后缀表达式
适用于输入为后缀表达式的场景(如35+表示3+5),修复后的代码完善了错误检查与运算符支持:
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> typedef struct Stack { int top; unsigned capacity; int *array; } Stack; Stack *createStack(unsigned capacity) { Stack *stack = (Stack *)malloc(sizeof(Stack)); stack->capacity = capacity; stack->top = -1; stack->array = (int *)malloc(stack->capacity * sizeof(int)); return stack; } int isEmpty(Stack *stack) { return stack->top == -1; } int peek(Stack *stack) { return stack->array[stack->top]; } int pop(Stack *stack) { if (!isEmpty(stack)) return stack->array[stack->top--]; fprintf(stderr, "Error: Stack underflow!\n"); exit(EXIT_FAILURE); } void push(Stack *stack, int op) { if (stack->top == stack->capacity - 1) { fprintf(stderr, "Error: Stack overflow!\n"); exit(EXIT_FAILURE); } stack->array[++stack->top] = op; } int evaluate(char *expression) { Stack *stack = createStack(strlen(expression)); int i; int len = strlen(expression); for (i = 0; i < len; ++i) { if (isspace(expression[i])) { continue; } else if (isdigit(expression[i])) { int operand = 0; while (i < len && isdigit(expression[i])) operand = operand * 10 + expression[i++] - '0'; --i; push(stack, operand); } else { if (stack->top < 1) { fprintf(stderr, "Error: Invalid expression!\n"); exit(EXIT_FAILURE); } int operand1 = pop(stack); int operand2 = pop(stack); switch (expression[i]) { case '+': push(stack, operand2 + operand1); break; case '-': push(stack, operand2 - operand1); break; case '*': push(stack, operand2 * operand1); break; case '/': if (operand1 == 0) { fprintf(stderr, "Error: Division by zero!\n"); exit(EXIT_FAILURE); } push(stack, operand2 / operand1); break; default: fprintf(stderr, "Error: Unsupported operator '%c'\n", expression[i]); exit(EXIT_FAILURE); } } } if (stack->top != 0) { fprintf(stderr, "Error: Invalid expression!\n"); exit(EXIT_FAILURE); } int result = pop(stack); free(stack->array); free(stack); return result; } int main() { char expression[100]; int choice; do { printf("\n菜单:\n"); printf("1. 计算算术表达式(后缀表达式)\n"); printf("2. 退出\n"); printf("请输入选择: "); scanf("%d", &choice); while (getchar() != '\n'); switch (choice) { case 1: printf("请输入后缀表达式(如35+表示3+5): "); fgets(expression, sizeof(expression), stdin); expression[strcspn(expression, "\n")] = '\0'; int result = evaluate(expression); printf("结果: %d\n", result); break; case 2: printf("再见!\n"); break; default: printf("无效选择,请重试。\n"); break; } } while (choice != 2); return 0; }
场景2:支持中缀表达式求值
适用于输入为普通中缀表达式的场景(如3+5*2),新增中缀转后缀的逻辑,处理运算符优先级与括号:
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> typedef struct Stack { int top; unsigned capacity; char *array; } CharStack; typedef struct IntStack { int top; unsigned capacity; int *array; } IntStack; CharStack *createCharStack(unsigned capacity) { CharStack *stack = (CharStack *)malloc(sizeof(CharStack)); stack->capacity = capacity; stack->top = -1; stack->array = (char *)malloc(stack->capacity * sizeof(char)); return stack; } int isCharEmpty(CharStack *stack) { return stack->top == -1; } char charPeek(CharStack *stack) { return stack->array[stack->top]; } char charPop(CharStack *stack) { if (!isCharEmpty(stack)) return stack->array[stack->top--]; return '\0'; } void charPush(CharStack *stack, char op) { if (stack->top == stack->capacity - 1) { fprintf(stderr, "Error: Stack overflow!\n"); exit(EXIT_FAILURE); } stack->array[++stack->top] = op; } IntStack *createIntStack(unsigned capacity) { IntStack *stack = (IntStack *)malloc(sizeof(IntStack)); stack->capacity = capacity; stack->top = -1; stack->array = (int *)malloc(stack->capacity * sizeof(int)); return stack; } int isIntEmpty(IntStack *stack) { return stack->top == -1; } int intPeek(IntStack *stack) { return stack->array[stack->top]; } int intPop(IntStack *stack) { if (!isIntEmpty(stack)) return stack->array[stack->top--]; fprintf(stderr, "Error: Stack underflow!\n"); exit(EXIT_FAILURE); } void intPush(IntStack *stack, int op) { if (stack->top == stack->capacity - 1) { fprintf(stderr, "Error: Stack overflow!\n"); exit(EXIT_FAILURE); } stack->array[++stack->top] = op; } int precedence(char op) { switch(op) { case '+': case '-': return 1; case '*': case '/': return 2; default: return 0; } } void infixToPostfix(char *infix, char *postfix) { CharStack *stack = createCharStack(strlen(infix)); int i = 0, j = 0; int len = strlen(infix); while (i < len) { if (isspace(infix[i])) { i++; continue; } if (isdigit(infix[i])) { while (i < len && isdigit(infix[i])) { postfix[j++] = infix[i++]; } postfix[j++] = ' '; } else if (infix[i] == '(') { charPush(stack, infix[i++]); } else if (infix[i] == ')') { while (!isCharEmpty(stack) && charPeek(stack) != '(') { postfix[j++] = charPop(stack); postfix[j++] = ' '; } charPop(stack); i++; } else { while (!isCharEmpty(stack) && precedence(charPeek(stack)) >= precedence(infix[i])) { postfix[j++] = charPop(stack); postfix[j++] = ' '; } charPush(stack, infix[i++]); } } while (!isCharEmpty(stack)) { postfix[j++] = charPop(stack); postfix[j++] = ' '; } postfix[j-1] = '\0'; free(stack->array); free(stack); } int evaluatePostfix(char *postfix) { IntStack *stack = createIntStack(strlen(postfix)); int i = 0; int len = strlen(postfix); while (i < len) { if (isspace(postfix[i])) { i++; continue; } else if (isdigit(postfix[i])) { int operand = 0; while (i < len && isdigit(postfix[i])) { operand = operand * 10 + postfix[i++] - '0'; } intPush(stack, operand); } else { int operand1 = intPop(stack); int operand2 = intPop(stack); switch(postfix[i]) { case '+': intPush(stack, operand2 + operand1); break; case '-': intPush(stack, operand2 - operand1); break; case '*': intPush(stack, operand2 * operand1); break; case '/': if (operand1 == 0) { fprintf(stderr, "Error: Division by zero!\n"); exit(EXIT_FAILURE); } intPush(stack, operand2 / operand1); break; } i++; } } int result = intPop(stack); free(stack->array); free(stack); return result; } int evaluateInfix(char *expression) { char postfix[200]; infixToPostfix(expression, postfix); return evaluatePostfix(postfix); } int main() { char expression[100]; int choice; do { printf("\n菜单:\n"); printf("1. 计算算术表达式(中缀表达式,如3+5*2)\n"); printf("2. 退出\n"); printf("请输入选择: "); scanf("%d", &choice); while (getchar() != '\n'); switch (choice) { case 1: printf("请输入中缀表达式: "); fgets(expression, sizeof(expression), stdin); expression[strcspn(expression, "\n")] = '\0'; int result = evaluateInfix(expression); printf("结果: %d\n", result); break; case 2: printf("再见!\n"); break; default: printf("无效选择,请重试。\n"); break; } } while (choice != 2); return 0; }
关键修复点说明
后缀表达式版本:
- 新增栈溢出/下溢、无效表达式的错误检查
- 扩展支持
*、/运算符,增加除零判断 - 提前计算表达式长度,避免循环内重复调用
strlen - 释放栈内存,避免内存泄漏
- 支持跳过输入中的空格
中缀表达式版本:
- 实现中缀转后缀逻辑,处理运算符优先级与括号
- 用空格分隔后缀表达式操作数,解决多位数解析问题
- 完善全流程错误处理机制
内容的提问来源于stack exchange,提问作者Progger_Pro
相关产品推荐
相关产品推荐

