以下是代码的实现使用gcc已经成功运行了,下面是效果图

#include <stdio.h>
#include <stdlib.h> #define OPT_ADD 43 /* + */
#define OPT_SUB 45 /* - */
#define OPT_MUL 42 /* * */
#define OPT_DIV 47 /* / */
#define L_BRACK 40 /* ( */ typedef struct _stack
{
int data; /* 栈内元素 */
struct _stack *next;
}Stack; /* 定义栈结构! */ /**
* 压栈
* 头插法,将数据压到头结点
**/
int push_stack(Stack **stack, int data)
{
Stack *p = (Stack*)malloc(sizeof(Stack));
if (NULL == p)
exit(-1); /* 申请内存都不行,挂了 */
p->data = data;
p->next = *stack;
*stack = p;
return 0;
} /**
* 弹栈
* 头指针就是栈顶
**/
int pop_stack(Stack **stack)
{
Stack *p = *stack; /* 缓存头指针 */
if (NULL == p)
return -1; /* 栈已经空了 */
int data = p->data; /* 缓存栈顶数据 */
*stack = p->next; /* 栈顶移动 */
free(p); /* 释放内存 */
return data;
} /**
* 获取栈顶元素
**/
int get_top_stack(Stack *stack)
{
return stack->data; /* 头指针就是栈顶 */
} /**
* 判断栈空
**/
int stack_is_empty(Stack *stack)
{
return NULL == stack ? 1 : 0;
} /**
* 栈内元素个数
**/
int count_stack(Stack *stack)
{
int cnt = 0;
while (NULL != stack)
{
cnt++;
stack = stack->next;
}
return cnt;
} /**
* 销毁栈
**/
void destroy_stack(Stack **stack)
{
Stack *p = *stack, *q;
while (NULL != p)
{
q = p->next;
free(p);
p = q;
}
*stack = NULL;
} /**
* 显示所有栈元素
**/
void show_stack(const char *name, Stack *stack)
{
printf("[%s: ", name);
while (NULL != stack)
{
printf("%d,", stack->data);
stack = stack->next; /* 从栈顶依次打印 */
}
printf("]\n");
} /**
* 计算a和b在mode符号的运算结果
**/
int cal(int a,int b,int mode)
{
int re = -1;
switch(mode)
{
case OPT_ADD: re = a + b; break;
case OPT_SUB: re = a - b; break;
case OPT_MUL: re = a * b; break;
case OPT_DIV: re = a / b; break;
default: break;
}
return re;
} /**
* 符号优先级判断
* 返回: 1(opt1>opt2) -1(opt1<opt2) 0(opt1=opt2)
* 注意符号的ASSIC码:43(+) 45(-) 42(*) 47(/)
**/
int opt_max(int opt1,int opt2)
{
if(OPT_MUL == opt1 || OPT_DIV == opt1)
{
if(OPT_ADD == opt2 || OPT_SUB == opt2)
{
return 1;
}
}
else
{
if(OPT_MUL == opt2 || OPT_DIV == opt2)
{
return -1;
}
}
return 0;
} /**
* 计算表达式
**/
int calculate(const char *expr)
{
int num1, num2, opt1, opt2;
Stack *num = NULL;
Stack *opt = NULL;
while ('\0' != *expr)
{
if ('(' == *expr)
{ /* 左括号 */
push_stack(&opt, (int)*expr++); /* 压符号栈 */
}
else if (')' == *expr)
{ /* 右括号 */
expr++; /* 指针加1 */
while (1)
{
if (L_BRACK == get_top_stack(opt))
{
pop_stack(&opt);
break; /* 如果当前栈顶是(则弾栈退出 */
}
else
{ /* 否则弾两个数字,一个符号进行运算 */
num2 = pop_stack(&num);
num1 = pop_stack(&num);
opt2 = pop_stack(&opt);
push_stack(&num, cal(num1, num2, opt2));
}
}
}
else if ('9' >= *expr && '0' <= *expr)
{ /* 数字 */
sscanf(expr, "%d", &num1);
push_stack(&num, num1);
num2 = 0; /* 记录num1的长度 */
while (0 != num1) {num2++; num1 /= 10;}
expr += num2; /* 指针移动指定长度 */
}
else if (*expr == OPT_ADD || *expr == OPT_SUB || *expr == OPT_MUL || *expr == OPT_DIV)
{ /* 加减乘除,这4个符号 */
opt1 = (int)*expr++;
while (1)
{
if (stack_is_empty(opt) || L_BRACK == get_top_stack(opt))
{
push_stack(&opt, opt1);
break;
}
else
{
opt2 = get_top_stack(opt);
if (0 < opt_max(opt1, opt2))
{ /* 当前获取的符号优先级大于栈顶符号 */
push_stack(&opt, opt1);
break;
}
else
{ /* 栈顶优先级高或者平级 */
num2 = pop_stack(&num);
num1 = pop_stack(&num);
opt2 = pop_stack(&opt);
push_stack(&num, cal(num1, num2, opt2));
}
}
}
} else {
printf("expression error\n");
num1 = -1; /* 这种是表达式错误 */
goto MUST_END;
}
} num1 = count_stack(num);
num2 = count_stack(opt);
if (num1 == 3 && num2 == 2) {
num2 = pop_stack(&num);
num1 = pop_stack(&num);
opt2 = pop_stack(&opt); /* 剩余3个数字和2个操作符,需要多计算一次 */
push_stack(&num, cal(num1, num2, opt2));
} else if (num1 == 2 && num2 == 1) {
/* 剩余2个数字和1个操作符,最后只计算1次 */
} else {
printf("expression error\n");
num1 = -1; /* 这种是表达式错误 */
goto MUST_END;
}
num2 = pop_stack(&num);
num1 = pop_stack(&num);
opt2 = pop_stack(&opt);
num1 = cal(num1, num2, opt2); MUST_END:
destroy_stack(&num); /* 销毁num栈 */
destroy_stack(&opt); /* 销毁opt栈 */
return num1;
} /**
* 主程序
* 放在最下面,避免重复声明函数
**/
int main(int argc, char *argv[])
{
if (argc == 2) {
printf("%s=%d\n", argv[1], calculate(argv[1]));
} else {
printf("usage:%s expression\n", argv[0]);
}
return 0;
}

至于原理嘛栈的操作我就不多叙述了。主要讲讲算法的事情,首先计算函数开始的时候就创建了数字栈和符号栈。处理的时候把所有字符串里取出来的东西都在栈里用整形保存,这样可以统一数字栈和符号栈是同种结构。当遍历字符串时遇到数字字符就把当前开始的数字取出来压数字栈,当遇到左括号是总是压符号栈不管连续多少个左括号,当遇到右括号时就从数字栈和符号栈中取值计算并从新压栈,直到遇到左括号,期间还要比较运算符的优先级等。当遇到字符串结束时还没有计算完成,此时数字栈和字符栈内都有值。如果数字栈为3个,符号栈为2个那么要计算两次,如果数字栈为2个,符号栈为1个计算一次。最终得出结果。我写这个程序时思路还是清晰的,就是不知道有没有小问题,希望能给大家一些启发。测试出问题也希望大家给我说,大家一起进步嘛。

C语言实现表达式求值,支持+、-、*、/四则运算,并且支持多级括号,自定义了栈的操作。的更多相关文章

  1. C语言中缀表达式求值(综合)

    题前需要了解的:中缀.后缀表达式是什么?(不知道你们知不知道,反正我当时不知道,搜的百度) 基本思路:先把输入的中缀表达式→后缀表达式→进行计算得出结果 栈:"先进先出,先进后出" ...

  2. 刁肥宅详解中缀表达式求值问题:C++实现顺序/链栈解决

    1. 表达式的种类 如何将表达式翻译成能够正确求值的指令序列,是语言处理程序要解决的基本问题,作为栈的应用事例,下面介绍表达式的求值过程. 任何一个表达式都是由操作数(亦称运算对象).操作符(亦称运算 ...

  3. C语言之四则运算表达式求值(链栈)—支持浮点型数据,负数, 整型数据运算

     运算符间的优先级关系: 链栈结构体定义: 数据域使用字符串长度为20的字符数组(故需要注意判断读取的字符串是运算符还是数值) 可支持浮点型数据,负数, 整型数据的运算 float EvaluateE ...

  4. 数据结构课程设计四则运算表达式求值(C语言版)

    本系统为四则运算表达式求值系统,用于带小括号的一定范围内正负数的四则运算标准(中缀)表达式的求值.注意事项:    1.请保证输入的四则表达式的合法性.输入的中缀表达式中只能含有英文符号"+ ...

  5. 数据结构算法C语言实现(八)--- 3.2栈的应用举例:迷宫求解与表达式求值

    一.简介 迷宫求解:类似图的DFS.具体的算法思路可以参考书上的50.51页,不过书上只说了粗略的算法,实现起来还是有很多细节需要注意.大多数只是给了个抽象的名字,甚至参数类型,返回值也没说的很清楚, ...

  6. 利用栈实现算术表达式求值(Java语言描述)

    利用栈实现算术表达式求值(Java语言描述) 算术表达式求值是栈的典型应用,自己写栈,实现Java栈算术表达式求值,涉及栈,编译原理方面的知识.声明:部分代码参考自茫茫大海的专栏. 链栈的实现: pa ...

  7. C/C++ 语言中的表达式求值(原文作者:裘宗燕)

    经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?”m = 1; n = m+++m++;最近有位不相识的朋友发email给我,问为什么在某个C++系统里,下面表达式打印出两个4, ...

  8. C/C++ 语言中的表达式求值

    在此,首先向裘老师致敬! 裘宗燕:C/C++ 语言中的表达式求值 经常可以在一些讨论组里看到下面的提问:“谁知道下面C语句给n赋什么值?” m = 1; n = m+++m++; 最近有位不相识的朋友 ...

  9. 表达式求值--数据结构C语言算法实现

    这篇博客介绍的表达式求值是用C语言实现的,只使用了c++里面的引用. 数据结构课本上的一个例题,但是看起来很简单,实现却遇到了很多问题. 这个题需要构建两个栈,一个用来存储运算符OPTR, 一个用来存 ...

随机推荐

  1. JVM调优和深入了解性能优化

    JVM调优的本质: 并不是显著的提高系统性能,不是说你调了,性能就能提升几倍或者上十倍,JVM调优,主要调的是稳定.如果你的系统出现了频繁的垃圾回收,这个时候系统是不稳定的,所以需要我们来进行JVM调 ...

  2. pwnable.kr之bof

    打开题目: 先下载题目给我们的两个文件,查看文件信息: 发现没有执行的权限,所以先增加文件bof的执行权限,执行: 没发现啥,然后查看代码, #include <stdio.h> #inc ...

  3. HTML标签语言一览表

    <html> ● 文件声明 让浏览器知道这是 html 文件 <head> ● 开头 提供文件整体资讯 <title> ● 标题 定义文件标题,将显示于浏览顶端 & ...

  4. oracle之三手工不完全恢复

    手工不完全恢复 4.1 不完全恢复的特点: 1)让整个database 回到过去某个时间点,不能避免数据丢失. 2)想跳过坏日志而继续恢复所有其他工作是不可能的,前滚没有这个功能(考点). 3)必须以 ...

  5. $\TeX$ Gyre 字体安装过程与问题解决

    目录 安装过程 1. 下载字体包 2. 安装字体 3. 测试范例文件 本文地址 https://www.cnblogs.com/oberon-zjt0806/p/13672426.html 本文只是一 ...

  6. [LeetCode] 22. 括号生成(回溯/DP)

    题目 给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合. 例如,给出 n = 3,生成结果为: [ "((()))", "(()( ...

  7. [SpringBoot项目]问题及解决总结

    问题:MySQL 8.0版本连接报错:Could not create connection to database server 原因 MySQL8.0版本需要更换驱动为"com.mysq ...

  8. Express下ejs的视图模板引擎的建立

    写在前面 由于Express升级到4.0,将ejs的用法忽略,改为用户自定义形式,所以要引入库index.js作为引擎,来支持ejs的模板引擎(点击下载). 首先是建立一个名字叫nodeitem,引擎 ...

  9. 用ajax获取后端数据,显示在前端,实现了基本计算器功能

    下午在看视频的时候,遇到一个问题:如何把后端 print_r或echo的数据显示在前端.百度了一下,说是用ajax,想着前一阵子学习了ajax,并且最近也想做一个计算器,于是就自己钻起来了. 计算器的 ...

  10. Win10 搭建FTP环境,并使用Java实现上传,下载,删除

    测试的环境一般都是在自己电脑上面装的,现在一般都使用Win10开发 搭建FTP: 第一步:打开控制面板:点击程序 第二步: 第三步: 然后点击确认后等待完成 完成后在启动中找到IIS管理器 打开 在网 ...