注:此文章代码参考:
https://blog.csdn.net/zwt0112/article/details/54562469
Help:
理解代码最好的途径,就是自己写个表达式跟着代码推一遍。
说明:
1.代码中自己找到的bug已经全部修改完,如果您有新的Bug发现,请留言说明。
2.代码实现了最简单的,整数的加减乘除(包含括号)运算。
3.自己写喜欢加注释,以及用printf验证代码,所以代码不太整洁。
/*****************************************************
File name:calculator
Author:lx 2018年10月15日
Description:可以作为简单的计算器,实现整数加,减,乘,除,以及带括号的运算
Calls : 1.insert_operand () 输入数据
2.insert_oper() 输入操作符
3.compare() 比较操作符优先级
4.deal_date() 进行数据处理
Attension:
1.注意输入的符号必须为英文半角
2.使用了栈先进后出的原则,此处栈为顺序栈
*****************************************************/
/*
字符串数组初始化0 与memset 0 效率的分析:https://www.cnblogs.com/x_wukong/p/5916618.html
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define MAX_SIZE 1024 //数组长度
//全局变量的定义
char *str = (char*)malloc(sizeof(char)*100); //声明一个字符指针,并让他指向申请内存的首地址处
int num_zhan[MAX_SIZE] = {0}; //初始化数据栈,顺序栈
int top_num = -1; //约定俗成
char yun_zhan[MAX_SIZE] = {0}; //运算符栈
int top_oper = -1;
//字符数组转int,注意不要理解错误,字符串是'\0'结尾的,程序可能不兼容
//网页链接:https://www.cnblogs.com/bluestorm/p/3168719.html
int str_to_num (char s[]) //原型 atio
{
int i,n,sign;
for(i=0;isspace(s[i]);i++);//跳过空白符;去了分号就不能用了,也是很神奇 ctype.h,
sign=(s[i]=='-')?-1:1;
if(s[i]=='+'||s[i]=='-')//跳过符号
i++;
for(n=0;isdigit(s[i]);i++) //保证是数
n=10*n+(s[i]-'0');//将数字字符转换成整形数字,简直不要太NB
return sign *n;
}
//数据进栈
void num_insert(int num)
{
//保证栈的内存足够
if(top_num+1<MAX_SIZE)
{
top_num = top_num+1;
num_zhan[top_num] = num;
}
else
{
printf("栈溢出了\n"); //可以用realloc重新分布内存
}
}
//操作符进栈
void char_insert(char change)
{
//保证栈的内存足够
if(top_num+1<MAX_SIZE)
{
top_oper = top_oper+1;
yun_zhan[top_oper] = change;
}
else
{
printf("栈溢出了\n"); //可以用realloc重新分布内存
}
}
//用于比较某字符和运算符栈定的优先级
//参考:https://blog.csdn.net/zwt0112/article/details/54562469
int priority(char compare)
{
/*
1.返回0,运算符进栈
2. 返回1,处理了括号
3.返回-1,作用很多,最重要的作用,就是将数据栈内的数据全部计算完就是靠的他,具体细节自己推演。
*/
//判断栈顶元素优先级
if((yun_zhan[top_oper] == '-'||yun_zhan[top_oper] =='+') && (compare == '*'||compare=='/'))
{
return 0;
}
//栈顶为空或者,进左括号,以及进了左括号后进入第一个非右括号元素
else if(top_oper== -1||compare =='('||(yun_zhan[top_oper] == '('&&compare !=')'))
{
return 0;
}
//处理(),即括号内运算符全部算完,后把括号消掉
else if(yun_zhan[top_oper] == '(' && compare == ')')
{
yun_zhan[top_oper] = 0;
top_oper--;
return 1;
}
//出栈 ,
else
{
return -1; //自己推一遍,你会发现你所有想不通的事儿,全是这个返回值在起作用去做那些事儿。
}
}
// 数据处理
int deal_date() /*进行数据运算*/
{
int num_1 = num_zhan[top_num]; /*取出数据栈中两个数据*/
int num_2 = num_zhan[top_num-1];
int value = 0;
if(yun_zhan[top_oper] == '+') /*加法操作*/
{
value = num_1 + num_2;
}
else if(yun_zhan[top_oper] == '-') /*减法操作*/
{
value = num_2 - num_1;
}
else if(yun_zhan[top_oper] == '*') /*乘法操作*/
{
value = num_2 * num_1;
}
else if(yun_zhan[top_oper] == '/') /*除法操作*/
{
value = num_2 / num_1;
}
top_num--; /*将数据栈顶下移一位*/
num_zhan[top_num] = value; /*将得到的值压入数据栈*/
top_oper--; /*将操作符栈顶下移一位*/
}
//判断是数字还是字符
int tell(char test)
{
if(test>='0'&&test<='9')
{
return 1;
}
else
{
return 0;
}
}
int main()
{
int test_flag = 0;
char num_buffer[100]={0}; //数字缓存,需要做到清除缓存。
int buffet_flag = 0;
int num;
int i;
/* 经验证,字符数组如果不赋予初值,则:
1.放在main函数里,默认初值随机数。
2.放在main函数外,默认初值为0
num_buffer[100]={0}经打印,这样初始化其内容为空
清空操作:choice1:赋值0
choic2:memset ;memset(num,'\0',sizeof(num)); 其实和赋值0一样,只不过可以直接调用了; 提示:#include <string.h>
*/
//屏幕提醒并输入
printf("请在下列输入要计算的表达式:\n");
scanf("%s",str);
while(*str !='\0') //循环直到字符结尾
{
//如果是数字
//提取连续的数字 ,不能用if_else选择结构,例如:if(是数字)怎样,else(操作数)怎样,因为这样会使得代码只运行两块中的一个,导致中间-1返回值失效,导致数据栈内剩余得数无法自动计算完 ,所以会发现连1+1都算不了。
while(tell(*str))
{
num_buffer[buffet_flag] = *str;
buffet_flag++;
str++; //important
}
//转为数字
if(buffet_flag > 0)
{
num = str_to_num(num_buffer);
// printf("%d",num);
//清空缓存区
memset(num_buffer,'\0',sizeof(num_buffer)); //位于string.h里
//刷新bufferflag
buffet_flag = 0;
//压入数据栈
num_insert(num);
}
//我自己写一定想不到,这里要用一个循环 ,这个循环和-1的结合真是恰到好处
while(1)
{
i = priority(*str); //判断优先级
if(i == 0)
{
char_insert(*str); //运算符进栈
break;
}
else if(i == 1) //括号结束,紧接着的一定是符号
{
str++;
}
else if(i == -1)
{
deal_date();
}
}
str++; //下一个
/*
for(i = 0; i < 20; i++)
{
printf("%d",num_zhan[i]);
}
printf("\n");
*/
}
printf("num = %d\n",num_zhan[0]); /*输出结果*/
return 0;
}
//3+(1+5)*2,此为自己的验证表达式