#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;
}
用C语言编写计算器代码到底是哪里错了😭
- 写回答
- 好问题 0 提建议
- 追加酬金
- 关注问题
- 邀请回答
-
1条回答 默认 最新
关注 本答案参考 多次询问 ChatGPT-3.5 后选择的最佳回答,若是满意,还请采纳,谢谢
初始化问题
- 在
main
函数中,当将初始运算符'#'
放入运算符栈时,代码optr.a[0] = '#'
后应该更新optr.top
指向正确的栈顶位置,即optr.top = optr.a+1;
。目前的代码虽然optr.top
在定义结构体时已经有了初始值指向optr.a
,但是直接对optr.a[0]
赋值后没有正确更新top
指针,可能导致后续操作出错。
- 在
逻辑问题 - 运算符处理
- 在
while (arr[i]!='=')
循环中的运算符处理部分:- 当
Compare(*optr.top, arr[i])== - 1
时,只是将当前运算符压入运算符栈然后i++
,但是没有考虑如果下一个字符是数字的情况,可能会导致数字的处理逻辑混乱。 - 当
Compare(*optr.top, arr[i])==0
时,只是弹出栈顶运算符,没有对这个运算符做任何处理,这里应该根据具体情况,比如如果是括号的匹配情况,可能不需要做进一步的操作,但是对于其他运算符可能需要进行计算操作。
- 当
- 在
逻辑问题 - 操作数处理
- 在
else
分支(处理数字的部分)中,当构建数字字符串d
时,没有考虑数字可能是多位的情况。例如,如果输入123
,目前的代码只会将1
转换为整数压入栈,而不是整个123
。
- 在
输出问题
- 在代码最后的输出部分,
printf("%d",opnd.a[2]);
这里直接输出opnd.a[2]
是不合理的,因为在整个计算过程中,结果应该在操作数栈的栈顶(由opnd.top
指向),而不是固定的opnd.a[2]
。并且在处理完剩余的运算符和操作数后,已经将操作数栈顶指针下移了一位,再输出*opnd.top
可能得到错误的结果。应该直接输出*opnd.top
而不需要前面单独输出opnd.a[2]
这一步。
- 在代码最后的输出部分,
栈空判断问题
- 在从操作数栈和运算符栈弹出元素的函数
Outopnd
和Outoptr
中,没有对栈空情况进行判断。如果栈已经为空还进行弹出操作会导致未定义行为。
- 在从操作数栈和运算符栈弹出元素的函数
除法运算问题
- 在
Operation
函数中的除法运算num = a / b;
没有考虑除数为0
的情况,这会导致程序崩溃。
- 在
内存管理问题(虽然在这个简单示例中不明显)
- 结构体
OPND
和OPTR
中的base
指针没有被充分利用,并且在定义结构体时可以直接初始化一些成员变量,使代码更加清晰。例如,可以在定义OPND
结构体时直接初始化stacksize
等成员变量。
- 结构体
代码风格和可读性
- 代码中的变量命名可以更加有意义,例如
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; }
这个修正后的代码解决了上述提到的部分问题,但仍然可以进一步优化,比如添加更多的错误处理和对输入表达式格式的严格检查等。
解决 无用评论 打赏 举报
悬赏问题
- ¥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模型图为什么和软件显示不一样?