写在前面
最近在写一个计算器的项目,其中最麻烦的就是数学表达试的解析,用C语言解决问题,每一步基本都要自己实现,非常锻炼逻辑能力。用了将近两个晚上的时间,终于完成了大部分表达式的解析,写这篇文章来记录下遇到的问题。
问题
动态字符串实现
最棘手的就是动态内存的分配,在这块遇到了很大的困难,经过百度,也是解决了问题。
参考链接:https://blog.youkuaiyun.com/ljwy1234/article/details/79036371
涉及到二维指针。
解析
这个程序主要解决的是括号,乘除,加减的运算优先级的处理。
参考链接:https://blog.youkuaiyun.com/yorhomwang/article/details/76691459
主要思想和这篇博客中的一样:
- 首先进行括号代换,就是将括号中的表达式单独计算出来,计算出来的字符串代替原来括号的位置。
- 然后进行乘除晕眩,将解析式中的乘除单独计算出来,计算出来的字符串代替原来乘除的位置。
- 最后进行加减法的运算,从左到右进行计算,得到结果。
代码中运用到了指针数组,数组中存放的都是指针,每个指针指向表达式中的子串。
这种方法可以运用于命令行参数的解析。
代码示例
代码可以直接运行
#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;
}