C语言堆栈实现最简单的计算器

注:此文章代码参考:

https://blog.csdn.net/zwt0112/article/details/54562469

Help:

理解代码最好的途径,就是自己写个表达式跟着代码推一遍。

说明:

1.代码中自己找到的bug已经全部修改完,如果您有新的Bug发现,请留言说明。

2.代码实现了最简单的,整数的加减乘除(包含括号)运算。

3.自己写喜欢加注释,以及用printf验证代码,所以代码不太整洁。

/*****************************************************  
File name:calculator  
Author:李翔   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 
*/ 

扫描二维码关注公众号,回复: 3735032 查看本文章

#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,此为自己的验证表达式

猜你喜欢

转载自blog.csdn.net/qq_40240102/article/details/83142531