补上之前四则运算计算器​​​​​​​的简单注释

时隔几年,补上之前四则运算计算器的简单注释

基本原理是:按优先级分解算式字符串

在分解加减运算时,以不在括号里的'+', '-'为分隔,分解字符串,返回计算结果

block0  =  block1 +(-) block2 +(-) block3

再对每个block分解乘除运算,以不在括号里的'+', '-'为分隔,分解字符串,返回计算结果

block3  =  block4 *(/) block5 *(/) block6

再对每个子block区分括号和数值

  • 对于括号(字符串以左括号开头):将括号内的字符串作为新的算式字符串,迭代计算该字符串,返回计算结果
  • 对于数值(字符串不左括号开头):将数值字符串转换为数值,返回数值

对于加减或乘除分解(这里以加减为例),每次提取出最右的一个block,再迭代分解左边的部分

block0  =  [ block1 ... block4 ] +(-) block5

[ block1 ... block4 ]  =  [ block1 ... block3 ] +(-) block4

...

至于为什么是从右边分解,因为加减(或乘除)运算是从左往右计算的,而在迭代的过程中,优先计算的是后迭代的内容

  • A - B + C  =  (A - B) + C
  • A - B + C  ≠  A - (B + C)

新注释过的代码

#include <stdio.h>
#define MAX_STR 10000

// 自己实现的 strlen
char *highofstr(char *low)
{
    while(*low!='\0')
        low++;
    return low-1;
}

// 把数值字符串转换为数值 
double trans(char *low, char *high)
{   
    double num=0;
    int cnt_point=-1;
    while(low<=high)
    {
        if( *low=='.' || cnt_point>-1 )
            cnt_point++;
        if( *low!='.' )
            num= 10*num+((*low)-'0');
        low++;
    }
    for( ; cnt_point>0; cnt_point--)
        num /=10;
    return num;
}

// 标记字符
// 数字、小数点 : 9
// +、- : 1
// *、/ : 2
// (、) : 迭代计算括号内字符串,结果视为数值,标记为9 
int flagch(char ch)
{
    if('0'<=ch && ch<='9')return 9;
    if(ch=='.')return 9; 
    if(ch=='+' || ch=='-')return 1;
    if(ch=='*' || ch=='/')return 2;
    if(ch=='(' || ch==')')return 9;
    return -1;
}

double deal_1(char *low, char *high);
double deal_2(char *low, char *high);
double deal_9(char *low, char *high);

// 优先级1(最低) 计算 +- : 
// 从右往左找括号栈为0的第一个+或-
// 计算 左 (+或-) 右
// 左 : 可能有括号外的+-,可能有括号外的*/,可能有() 
// 右 : 没有括号外的+-,可能有括号外的*/,可能有() 
double deal_1(char *low, char *high)
{
    int cnt_kh=0;
    char *p=high;
    while( (flagch(*p)!=1 && p>low) || (cnt_kh!=0) )
    {
        if(*p=='(')cnt_kh++;
        if(*p==')')cnt_kh--;
        p--;
    } 
    
    if(p<=low)
        return deal_2(low, high);
    else if(*p=='+')
        return deal_1(low, p-1)+deal_2(p+1, high);
    else if(*p=='-')
        return deal_1(low, p-1)-deal_2(p+1, high);
}

// 优先级2 计算 */ : 
// 从右往左找括号栈为0的第一个*或/
// 计算 左 (*或/) 右
// 左 : 没有括号外的+-,可能有括号外的*/,可能有() 
// 右 : 没有括号外的+-,没有括号外的*/,可能有() 
double deal_2(char *low, char *high)
{
    int cnt_kh=0;
    char *p=high;
     while( (flagch(*p)!=2 && p>low) || (cnt_kh!=0) )
    {
        if(*p=='(')cnt_kh++;
        if(*p==')')cnt_kh--;
        p--;
    } 
    
    if(p<=low)
        return deal_9(low, high);
    else if(*p=='*')
        return deal_2(low, p-1)*deal_9(p+1, high);
    else if(*p=='/')
        return deal_2(low, p-1)/deal_9(p+1, high);
}

// 优先级9(最高) 计算 () 或 数值转换: 
// 计算 括号内的内容 或 把数值字符串转换成数值 
// 把括号内的字符串视为新的计算字符串进行计算 
double deal_9(char *low, char *high)
{ 
    if( *low!='(' )
        return trans(low, high);
    else
        return deal_1(low+1, high-1);
}

/*
int true_cnt_point(double num)
{  
    if( num-(int)num==0 )return 0;
    return 1+true_cnt_point(num*10);
}
*/

// 按字符输入字符串, 跳过空格 
void Enterstr(char *str) {
    for(int i=0; i<MAX_STR; i++)
    {
        scanf("%c", str);
        if(*str=='\n')break;
        if(*str!=' ')str++; 
    } 
    *str='\0';
}
 
int main()
{
    char str[MAX_STR+1];
    while(1)
    {
        Enterstr(str);
        printf("%.10f\n", deal_1(str, highofstr(str)));
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值