数学计算表达式解析

写在前面

最近在写一个计算器的项目,其中最麻烦的就是数学表达试的解析,用C语言解决问题,每一步基本都要自己实现,非常锻炼逻辑能力。用了将近两个晚上的时间,终于完成了大部分表达式的解析,写这篇文章来记录下遇到的问题。

问题

动态字符串实现

最棘手的就是动态内存的分配,在这块遇到了很大的困难,经过百度,也是解决了问题。
参考链接:https://blog.youkuaiyun.com/ljwy1234/article/details/79036371
涉及到二维指针。

解析

这个程序主要解决的是括号,乘除,加减的运算优先级的处理。
参考链接:https://blog.youkuaiyun.com/yorhomwang/article/details/76691459
主要思想和这篇博客中的一样:

  1. 首先进行括号代换,就是将括号中的表达式单独计算出来,计算出来的字符串代替原来括号的位置。
  2. 然后进行乘除晕眩,将解析式中的乘除单独计算出来,计算出来的字符串代替原来乘除的位置。
  3. 最后进行加减法的运算,从左到右进行计算,得到结果。

代码中运用到了指针数组,数组中存放的都是指针,每个指针指向表达式中的子串。
这种方法可以运用于命令行参数的解析。

代码示例

代码可以直接运行

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

/****************************str*****************************/

char *str_init()
{
    char *p = (char *)malloc(1);
    p[0] = '\0';

    return p;
}

void str_free(char *p)
{
    free(p);
}

void str_append(char **src, const char *str)
{
    int len = strlen(*src) + strlen(str);

    char *str1_tmp = *src;  //保存原来指针位置
    *src = (char *)malloc(len + 1); //重新申请内存

    //操作
    strcpy(*src, str1_tmp);
    strcat(*src, str);
    (*src)[len] = '\0';

    free(str1_tmp);
}
/****************************str*****************************/


/****************************calculate*****************************/
void deal_split(char *a, int len, char *list[])
{
    int i = 0, j = 0;

    list[j++] = &a[0];
    for (i = 0; i < len; i++)
    {
        if (a[i] == ' ')
        {
            a[i] = '\0';
            list[j++] = &a[i + 1];
        }
    }
}

//加减
int deal_add_sub(char *str)
{
    //分割
    char *list[30] = { NULL };
    deal_split(str, strlen(str), list);

    int result = atoi(list[0]);
    int i = 0;
    for (i = 1; i < 10 && list[i] != NULL; i += 2)
    {
        if (*list[i] == '+')
        {
            result += atoi(list[i + 1]);
        }
        if (*list[i] == '-')
        {
            result -= atoi(list[i + 1]);
        }
    }
    return result;
}

//乘除
char *deal_mul_div(char *str)
{
    //分割
    char *list[30] = { NULL };
    deal_split(str, strlen(str), list);

    char *dst = str_init(); //输出字符串
    char *temp = list[0];

    char itoa_temp[10] = {0};

    int i = 0;
    for (i = 1; i < 30 && list[i] != NULL; i += 2)
    {
        if (*list[i] == '+')
        {
            str_append(&dst, temp);
            str_append(&dst, " + ");
            temp = list[i + 1];
        }
        else if (*list[i] == '-')
        {
            str_append(&dst, temp);
            str_append(&dst, " - ");
            temp = list[i + 1];
        }
        else if (*list[i] == '*')
        {
            int value = atoi(temp);
            value *= atoi(list[i + 1]);
            itoa(value, itoa_temp, 10);
            temp = itoa_temp;
        }
        else if (*list[i] == '/')
        {
            int value = atoi(temp);
            value /= atoi(list[i + 1]);
            itoa(value, itoa_temp, 10);
            temp = itoa_temp;
        }
    }
    str_append(&dst, temp);
    return dst;
}

void printf_list(char *list[])
{
    int iii = 0;
    for (iii = 0; iii < 30 && list[iii] != NULL; iii++)
    {
        printf("%s\n", list[iii]);
    }
}

//括号
char *deal_bracket(char *str)
{
    //分割
    char *list[30] = { NULL };
    deal_split(str, strlen(str), list);

    char *dst = str_init(); //输出字符串
    char *dst_temp = str_init();
    char *temp = list[0];

    char itoa_temp[10] = {0};

    int i = 0;
    for (i = 1; i < 30 && list[i] != NULL; i++)
    {
        if (*list[i] == '+')
        {
            str_append(&dst, temp);
            str_append(&dst, " + ");
            temp = list[i + 1];
        }
        else if (*list[i] == '-')
        {
            str_append(&dst, temp);
            str_append(&dst, " - ");
            temp = list[i + 1];
        }
        else if (*list[i] == '*')
        {
            str_append(&dst, temp);
            str_append(&dst, " * ");
            temp = list[i + 1];
        }
                else if (*list[i] == '/')
        {
            str_append(&dst, temp);
            str_append(&dst, " / ");
            temp = list[i + 1];
        }
        else if (*list[i] == '(')
        {
            i++;
            str_append(&dst_temp, list[i]);

            i++;
            while (*list[i] != ')')
            {
                str_append(&dst_temp, " ");
                str_append(&dst_temp, list[i]);
                i++;
            }

            char *p1 = deal_mul_div(dst_temp);
            int value = deal_add_sub(p1);

            itoa(value, itoa_temp, 10);
            temp = itoa_temp;
        }
    }
    str_append(&dst, temp);

    str_free(dst_temp);
    return dst;
}

/****************************calculate*****************************/

int main()
{
    char a[100] = "6 / 2 + ( 2 * 5 + 2 * 2 ) - 9 / 3";
    printf("original = %s\n", a);
    char *p = deal_bracket(a);
    printf("bracket  = %s\n", p);
    char *pp = deal_mul_div(p);
    str_free(p);
    printf("mul_div  = %s\n", pp);
    int ppp = deal_add_sub(pp);
    str_free(pp);
    printf("result   = %d\n", ppp);

    return 0;
}

反思

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chasentech

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值