C语言:(旧)用字符串自由输入计算的计算器(加减乘除)

已更新:功能更强的新版计算器代码点击这里

小学期课里老师曾让写一个能够自由输入并计算的计算器,例如:3-5+2,计算结果为0 第一次尝试不断修改字符串来计算,但是发现十分容易出错
第二次改用读入变量和运算符的方法来计算结果,没学过数据结构,过程略微复杂,目前没发现计算错误,欢迎提出错误~o( ̄▽ ̄)o
暂不支持输入负数和带()的计算

UPDATE:支持了小数
UPDATE:修正了被除数是小数读取错误的问题,保留小数位数增加
UPDATE:加入了死循环,优化了在Linux终端的体验

存储模式图解:
这里写图片描述

已测试数据:
数据                      结果
5+5                          10.000
5+5*2                        15.000
5+5/2                         7.500
5+5*2+4/8                    15.500
2*2*2+6/3+7-5                12.000
6-4+5*6                      32.000
20+10*5*2+10/5*6            132.000
6-2*2                         2.000
10-2*5/2                      5.000
56+2-44-6/3*5-7+10*2/4        2.000
6/40*3.1-100+799/3          166.798
330/99*10+90*3.2-20/8.2     318.894
4.4/2.2                       2.000

代码如下:

#include<stdio.h>
#include<stdlib.h>
#define dataNums 300

struct calculator
{//以运算符为中心,存储左右两边的值
    double leftData;
    char operators;
    double rightData;
};
int *Book;//用于记录废弃的结构体变量,大小由运算符个数决定
int getNumbersOfoperators(char *string)
{//数出运算符的个数,以此申请内存
    int i=0,count=0;
    while (string[i] != '\0')
    {
        if (string[i] == '+' || string[i] == '-' || string[i] == '*' || string[i] == '/')
            ++count;

        ++i;
    }
    return count;
}
double StringToDouble(char *string,int hasDot)
{
    int i = 0;
    double num = 0;
    double times = 1;

    if (hasDot == 1)
    {
        while (string[i] != '.')
        {
            ++i;
        }
    }
    else
    {
        while (string[i] != '\0')
        {
            ++i;
        }
    }
    --i;
    while (string[i] >= '0'&&string[i] <= '9')
    {
        num += (string[i] - 48)*times;
        times *= 10;
        --i;
    }
    if (hasDot == 1)
    {
        times = 0.1;
        i = 0;
        while (string[i] != '.')
        {
            ++i;
        }
        ++i;
        while (string[i] != '\0')
        {
            num += (string[i] - 48)*times;
            times /= 10;
            ++i;
        }
    }

    return num;
}
double getFrontNumber(int calplace, char *string)
{//找到运算符后读取其前一位数字
    int i = calplace - 1;
    int j = 0;
    int hasDot = 0;
    char tempNum[50];

    while (string[i] >= 48 && string[i] <= 57 || string[i] == '.')
        --i;
    ++i;
    for (j = 0; string[i] >= 48 && string[i] <= 57 ||string[i]=='.'; j++,i++)
    {
        if (string[i] == '.')
        {
            hasDot += 1;
            if (hasDot > 1)
            {
                puts("Data error!");
                system("pause");
                exit(0);
            }
        }
        tempNum[j] = string[i];
    }
    tempNum[j] = '\0';

    return StringToDouble(tempNum, hasDot);
}
double getAfterNumber(int calplace, char *string)
{//读取其后一位数字
    int i = calplace + 1;
    int j;
    char tempNum[50];
    int hasDot = 0;

    for (j = 0; string[i] >= 48 && string[i] <= 57 || string[i] == '.'; j++, i++)
    {
        if (string[i] == '.')
        {
            hasDot += 1;
            if (hasDot > 1)
            {
                puts("Data error!");
                system("pause");
                exit(0);
            }
        }
        tempNum[j] = string[i];
    }
    tempNum[j] = '\0';

    return StringToDouble(tempNum, hasDot);
}
struct calculator *getData(char *string,int pairSize)
{//把输入字符串里的数字存入申请的结构体里,例如2+5*2,存为2 + 5, 5 * 2
    struct calculator *pairNums;
    int i = 0;
    int j = 0;

    pairNums = (struct calculator *)calloc(pairSize, sizeof(struct calculator));//申请内存
    Book=(int *)calloc(pairSize,sizeof(int));//申请记录废弃变量的数组

    for (i = 0; string[i] != '\0'; i++)
    {
        if (string[i] == '+' || string[i] == '-' || string[i] == '*' || string[i] == '/')
        {//每个运算符左右两侧都有值,找出并存入结构体变量里
            pairNums[j].operators = string[i];

            pairNums[j].leftData = getFrontNumber(i, string);
            pairNums[j].rightData = getAfterNumber(i, string);

            ++j;
        }
    }
    return pairNums;
}
float getResult(struct calculator *pairNums,int pairSize)
{//计算并返回最终结果
    double tempResult=0;
    double temp;//单次计算结果
    int i;
    int j;
    int flag=0;//记录是否需要更改前后结构体的值
    int setZero=0;//单次结果是否归零

    for(i = 0;i<pairSize;i++)//优先计算*/有关的数组
    {
        temp=0;
        if(pairNums[i].operators=='*')
        {
            flag=1;
            temp= pairNums[i].leftData *1.0* pairNums[i].rightData;
        }
        if(pairNums[i].operators=='/')
        {
            flag=1;
            temp= pairNums[i].leftData*1.0/pairNums[i].rightData;
        }

        if(flag==1)//每次/*计算后需要改变前后数组的变量值
        {
            flag=0;//归零
            if(i-1!=-1)//改变前一个数组的值,条件:非首位
            {
                j=i-1;
                while(Book[j]==1)//找到最近一个未被废弃的数组
                { 
                    --j;
                }
                if(pairNums[j].operators=='+')
                {
                    pairNums[j].rightData=0;
                }
                else if(pairNums[j].operators=='-')
                {
                    pairNums[j].rightData=temp; //+和-的操作不同
                    Book[i]=1;//给出i位置的计算结果并赋给前一个未废弃且带'-'号的数组
                    setZero=1;//临时的计算结果temp归零为真
                }

            }
            if(i+1!=pairSize)//改变后一个数组的left值,条件:非末位
            {
                j=i+1;
                while(Book[j]==1)
                {
                    ++j;
                }
                if(pairNums[j].operators!='*' && pairNums[j].operators!='/')
                {
                    pairNums[j].leftData=0;//将下一个数组(非*/计算)的leftdata归零
                }
                else
                {
                    pairNums[j].leftData=temp;//如果为*/计算,则赋予temp计算内容
                    Book[i]=1;//废弃当前数组
                    setZero=1;//单次计算结果归零
                }
            }

        }
        if(setZero==1)//是否需要归零当前数组单次计算的结果
        {
            setZero=0;
            temp=0;
        }
        tempResult+=temp;//将单次的计算结果汇入总结果
    }
    for(i = 0;i<pairSize;i++)//计算+-运算
    {
        if(pairNums[i].operators=='+')
        {
            tempResult += pairNums[i].leftData+pairNums[i].rightData;
            flag=1;
        }
        if(pairNums[i].operators=='-')
        {
            tempResult += pairNums[i].leftData-pairNums[i].rightData;
            flag=1;
        }
        if(flag==1)
        {
            flag=0;

            if(i+1!=pairSize)
            {
                if(pairNums[i+1].operators=='+' || pairNums[i+1].operators=='-')
                {
                    pairNums[i+1].leftData=0;
                }
            }
        }

    }
    return tempResult;//返回计算结果
}
int main()
{
    float result;
    struct calculator *pairNums;
    char inputData[dataNums];
    int count_Calculators = 0;//记录运算符个数
    puts("input your formula and  'q' to quit!");
    while(1)
    {
        scanf("%s",inputData);//输入字符串(计算式)
        if(inputData[0]=='q')//唯一退出出口
        {
            free(Book);
            free(pairNums);
            return 0; 
        }

        count_Calculators = getNumbersOfoperators(inputData);//得到运算符个数
        pairNums = getData(inputData,count_Calculators);//将字符串中的数组两两一组汇入结构体数组里
        result=getResult(pairNums,count_Calculators);//计算结果

        printf("Result=%.6lf\n",result);

        free(Book);
        free(pairNums);
   }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值