计算器是栈的教科书级应用。这个项目从 V1.0 迭代到 V1.2,最终版约 1100 行,从”能算 1+2*3“一路做到:+ - * / ^ 五则运算、{} [] () 三种括号混用、小数,甚至 sin(1+sin(1+sin(1))) 这样的嵌套函数调用——全部纯 C 手写。
核心算法:两个栈消灭优先级
人脑算 3 + 4 * 2 时知道先乘除后加减,机器靠两个栈来消灭优先级问题:
- 数字栈:存放操作数
- 符号栈:存放运算符,利用优先级决定何时计算
整个算法分两步:
- 中缀转后缀:将
3 + 4 * 2 转为 3 4 2 * +(后缀表达式/逆波兰式),后缀表达式不需要任何优先级判断
- 后缀求值:逐个读 token,数字入栈,运算符弹出两个数计算后与压回,最后栈里剩下的就是答案
先造工具:My_Stack
写计算器之前先造轮子。栈用 calloc 分配、realloc 扩容,base/top/max 三个指针管理一段连续内存:
1 2 3 4 5 6 7
| struct my_Stack { ll stack_size; Elemtype* base; Elemtype* top; Elemtype* max; };
|
Elemtype 用宏定义成 int,ll 是 long int 的别名——这套栈天生是为”下标入栈”准备的(后面会看到为什么)。压栈前检查满栈,满了就扩容一倍;弹栈前检查空栈:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| bool Push(struct my_Stack* Stack, Elemtype ele) { if(Stack_full(Stack) == true) { if(Stack_new(Stack,Stack->stack_size * 2) == false) { return false; } } *Stack->top = ele; Stack->top++; return Stack_OK; }
Elemtype Pop(struct my_Stack* Stack) { if(Stack_empty(Stack) == true) { printf("弹栈失败:这个栈已经是空的了.\n"); return ~(unsigned int)0/2; } else { Stack->top--; return *Stack->top; } }
|
空栈弹栈的返回值 ~(unsigned int)0/2 是 int 的最大值——用一个”不可能出现的数”当错误码,调用方拿到它就知道弹栈失败了。除了 Push/Pop,还有 Stack_init(calloc 初始化)、Stack_new(realloc 扩容)、Stack_empty/Stack_full、Stack_clear(top 指回 base)和 Stack_destory(free)一整套接口,全部配了 Doxygen 注释——这个习惯一直保留到了后来的 Print 项目。
表达式在内存里长什么样
一个 token 要么是数字,要么是运算符,用两个指针表示:
1 2 3 4 5
| struct ele { char *p_opt; double *p_num; };
|
所有数字统一存进 double num[100],运算符存进 char opt[100],token 数组里只放指针。这样转后缀、求值的时候搬运的都是小小的 struct ele,不用拷贝数据本身。
预处理:把表达式洗干净
用户输入什么都有可能。入口函数 calc() 先做几件”洗数据”的活:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| double calc(char *str) { double result = 0; struct ele postfix_Expression[100]; memset(postfix_Expression, 0, sizeof(postfix_Expression));
char new_str[100]; memset(new_str, 0, sizeof(new_str)); new_str[0] = '0'; new_str[1] = '+'; strcpy(new_str+2, str);
for (int i = 0; i < sizeof(new_str); i++) { if(new_str[i] == '[' || new_str[i] == '{') { new_str[i] = '('; } else if(new_str[i]== ']' || new_str[i] == '}') { new_str[i] = ')'; } }
str_find_exp_and_calc(new_str); printf("str_find_exp_and_calc : %s\n", new_str);
mid_to_back(new_str, strlen(new_str), postfix_Expression); result = caculate_four_arithmetic_operations(postfix_Expression);
return result; }
|
- 开头拼一个
0+:-1+2 变成 0-1+2,负号从”一元运算符”降级成普通的二元减号,后面的算法完全不用为它设计特判
- 三种括号归一化:
{ [ 全换成 (,} ] 全换成 )——对求值来说它们语义相同,没必要区别对待
- 先算函数:
str_find_exp_and_calc 会把表达式里所有 sin(...)、sqrt(...) 直接换成算好的数值(后面细讲),四则运算拿到的就永远是纯数字表达式
接下来拆 token。先把每个字符标记成”符号/非符号”的掩码数组 opt_idx,再把相邻的非符号位合并成一位——多位数字和小数点属于同一个数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| for(i = 0 ; i < len ; ++i) { if(str[i] == '[' || str[i] == '{') { str[i] = '('; } else if(str[i] == ']' || str[i] == '}') { str[i] = ')'; }
if(str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' || str[i] == '^' || str[i] == '(' || str[i] == ')') { opt[count_opt] = str[i]; opt_idx[i] = 1; count_opt++; } else { opt_idx[i] = 0; } }
for(int i = 0; i < 99; ++i) { if(opt_idx[i] == 0 && opt_idx[i+1] == 0) { for(int j = i; j < 99; ++j) { opt_idx[j] = opt_idx[j+1]; } i--; } }
|
数字本体用 strtok 按 +-*/^() 切开、atof 转 double:
1 2 3 4 5 6
| p = strtok(str, "+-*/^()"); num[0] = atof(p); while((p = strtok(NULL, "+-*/^()"))) { num[count_num++] = atof(p); }
|
最后把 num 数组和 opt 数组按掩码交错装进 struct ele 数组,中缀表达式就在内存里排好了队。
中缀转后缀
遍历中缀表达式的每个 token,规则只有四条:
- 数字 → 直接加入结果
- 左括号
( → 直接入符号栈
- 右括号
) → 不断弹栈进结果,直到碰见左括号
- 运算符 → 与栈顶比优先级:严格大于才入栈;否则不断弹栈进结果,直到能入栈为止
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
| struct my_Stack Stack_calculate; struct ele postfix_Expression[100]; ll count_postfix_idx = 0;
Stack_init(&Stack_calculate); char opt_cal; ll opt_temp_idx = 0; char opt_temp[100]; char opt_top;
for(i = 0; i < 100; ++i) { postfix_Expression[i].p_num = NULL; postfix_Expression[i].p_opt = NULL; }
for (i = 0; i < max_idx; ++i) { if(infix_expression[i].p_num != NULL) { postfix_Expression[count_postfix_idx] = infix_expression[i]; count_postfix_idx++; } else if(infix_expression[i].p_opt != NULL) { opt_cal = *infix_expression[i].p_opt; if( opt_cal == '(') { Push(&Stack_calculate,opt_cal); continue; } if( opt_cal != ')') { if(Stack_empty(&Stack_calculate) == true) { opt_top = ' '; } else { opt_top = *(Stack_calculate.top-1); } if(Priority(opt_cal) > Priority(opt_top)) { Push(&Stack_calculate,opt_cal); } else { while(Priority(opt_cal) <= Priority(opt_top)) { if(Stack_empty(&Stack_calculate) == true || *(Stack_calculate.top-1) == '(') { break; } opt_top = Pop(&Stack_calculate); opt_temp[opt_temp_idx] = opt_top; postfix_Expression[count_postfix_idx].p_opt = &opt_temp[opt_temp_idx]; postfix_Expression[count_postfix_idx].p_num = NULL; count_postfix_idx++; opt_temp_idx++; } Push(&Stack_calculate,opt_cal); } } else { char char_tmp = 0; while(char_tmp != '(') { char_tmp = Pop(&Stack_calculate); if(char_tmp == '(') { break; } opt_temp[opt_temp_idx] = char_tmp; postfix_Expression[count_postfix_idx].p_opt = &opt_temp[opt_temp_idx]; postfix_Expression[count_postfix_idx].p_num = NULL; opt_temp_idx++; count_postfix_idx++; } } } }
while(Stack_empty(&Stack_calculate) == false) { opt_top = Pop(&Stack_calculate); opt_temp[opt_temp_idx] = opt_top; postfix_Expression[count_postfix_idx].p_opt = &opt_temp[opt_temp_idx]; postfix_Expression[count_postfix_idx].p_num = NULL; opt_temp_idx++; count_postfix_idx++; }
|
注意比较用的是严格大于:同优先级的运算符会先把栈里的弹出来、再让新的入栈,保证 8-3-2 按 (8-3)-2 从左到右算——这是左结合。这里如果写成 >=,连续的减法除法就会算反。循环结束后把符号栈里剩的符号全部弹进结果,中缀就变成了后缀。
后缀求值:下标入栈
求值有个小障碍:栈的 Elemtype 是 int,要存的却是 double。把栈改成 double 也行,但这里的解法更轻:double 全放在 num_tmp 数组里,栈里只压下标。数字 token 到来时压的是它的下标;遇到运算符就弹两个下标,取数计算,结果追加到 num_tmp 尾部,再把新结果的”下标”压回去:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| ll max_idx = count; ll max_idx_count = 0;
count = 0; for (int i = 0; i < 100; ++i) { if(postfix_Expression[i].p_num != NULL) { Push(&Stack_calculate,count); count++; continue; } if(postfix_Expression[i].p_opt != NULL) { ll num_1_idx = Pop(&Stack_calculate); ll num_2_idx = Pop(&Stack_calculate); switch (*postfix_Expression[i].p_opt) { case '^': { num_tmp[max_idx+max_idx_count] = pow(num_tmp[num_2_idx],num_tmp[num_1_idx]); Push(&Stack_calculate,max_idx+max_idx_count); max_idx_count++; break; } case '+': { num_tmp[max_idx+max_idx_count] = num_tmp[num_2_idx] + num_tmp[num_1_idx]; Push(&Stack_calculate,max_idx+max_idx_count); max_idx_count++; break; } case '-': { num_tmp[max_idx+max_idx_count] = num_tmp[num_2_idx] - num_tmp[num_1_idx]; Push(&Stack_calculate,max_idx+max_idx_count); max_idx_count++; break; } case '*': { num_tmp[max_idx+max_idx_count] = num_tmp[num_2_idx] * num_tmp[num_1_idx]; Push(&Stack_calculate,max_idx+max_idx_count); max_idx_count++; break; } case '/': { num_tmp[max_idx+max_idx_count] = num_tmp[num_2_idx] / num_tmp[num_1_idx]; Push(&Stack_calculate,max_idx+max_idx_count); max_idx_count++; break; } default: break; } continue; } }
|
有个容易翻车的细节:先弹出的是右操作数。减法、除法、幂都不满足交换律,num_2_idx 和 num_1_idx 的顺序反了,8/2 就变 2/8 了。全部 token 走完,栈里剩下的那个下标指向的就是最终答案。
数学函数:函数指针查找表 + 递归
sin(3.1415926/2) 这种怎么算?思路是在四则运算之前,先把表达式里的函数调用全部换成数值。str_find_exp_and_calc 从左到右扫描,看到 ( 且前一个字符不是运算符也不是另一个 (——说明这个括号头上挂着函数名。函数名是倒着往回抠的,抠完把字符串反转回来;参数则用计数器做括号匹配:遇到 ( 加一、遇到 ) 减一,归零时正好是最外层右括号——不管参数里嵌了多少层括号都能完整抠出来。
15 个数学函数的”查找表”,是一串 strcmp 加函数指针:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| typedef double (*math_fun)(double); math_fun get_math_fun(const char *s) { if (strcmp(s, "sin") == 0) { return sin; } else if (strcmp(s, "cos") == 0) { return cos; } else if (strcmp(s, "tan") == 0) { return tan; } else { return NULL; } }
|
参数表达式里可能还嵌着函数,所以直接递归调用 calc():
1 2 3 4 5
| strcpy(str_temp, exp_strs[i]); double temp = calc(exp_strs[i]); strcpy(exp_strs[i], str_temp);
char *temp_result_str = double2str(get_math_fun(exp_funcs[i])(temp));
|
sin(1+sin(1+sin(1))) 就是这样一层层递归进去、一层层替换回来的。算出的结果替换回原字符串时还有个细节:负数结果要包成 (0-x),否则替换回去的一元负号会让后面的四则运算翻车:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| if(exp_strStuct.exp_results[i][0] == '-') { char *temp = exp_strStuct.exp_results[i]; exp_strStuct.exp_results[i] = (char *)malloc(sizeof(char) * (strlen(exp_strStuct.exp_results[i]) + 3)); memset(exp_strStuct.exp_results[i], 0, sizeof(char) * (strlen(exp_strStuct.exp_results[i]) + 3));
exp_strStuct.exp_results[i][0] = '('; exp_strStuct.exp_results[i][1] = '0'; strcpy(exp_strStuct.exp_results[i] + 2, temp); exp_strStuct.exp_results[i][strlen(exp_strStuct.exp_results[i])] = ')';
free(temp); }
|
运行效果
main.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #include <stdio.h> #include "calc.h"
int main() { char exp[100] = "1+2*3/4"; printf("%lf\n",calc(exp)); return 0; }
|
测试用的表达式一直留在注释里,从整数四则、三种括号混用,到 sin/cos/sqrt/log10/exp 嵌套调用,就是这个项目能力范围的一份清单。
版本迭代
- V1.0:
calc.c + My_Stack.c/.h 跑通主流程——双栈转后缀、下标入栈求值,配了一个”多文件编译并链接”的 .bat 脚本
- V1.1:测试验证版,代码和 V1.0 基本一致,主要在换测试用例(比如
1/(9))做边界验证
- V1.2:模块化整理——
struct ele 和调试宏抽进 calc.h;新增 func_calc.c/.h 数学函数模块(函数指针表 + 括号匹配 + 递归求值);顺手修了 num[] 未初始化、掩码合并循环边界(50→99)两个小 bug
V1.2 完整代码
项目一共 7 个文件,main.c 已在上面贴出,其余 6 个按依赖顺序全部贴出。
My_Stack.h
My_Stack.h1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #ifndef _My_Stack_H_ #define _My_Stack_H_
#include <stdio.h> #include <stdlib.h> #define Elemtype int
#define bool char
#define Stack_OK 0 #define true 1 #define false 0
#define init_element_num 100 #define init_error -1
typedef long int ll;
struct my_Stack { ll stack_size; Elemtype* base; Elemtype* top; Elemtype* max; };
bool Stack_init(struct my_Stack* Stack); bool Stack_new(struct my_Stack* Stack, ll num); bool Stack_destory(struct my_Stack* Stack);
ll Stack_get_len(struct my_Stack* Stack); bool Stack_empty(struct my_Stack* Stack); bool Stack_full(struct my_Stack* Stack);
void Stack_clear(struct my_Stack* Stack); bool Push(struct my_Stack* Stack, Elemtype ele);
Elemtype Pop(struct my_Stack* Stack);
#endif
|
My_Stack.c
My_Stack.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
| #include <stdio.h> #include <stdlib.h> #include "My_Stack.h"
bool Stack_init(struct my_Stack* Stack) { Stack->base = (Elemtype *)calloc(sizeof(Elemtype),init_element_num); if(Stack->base == NULL) { return init_error; } Stack->stack_size = init_element_num; Stack->top = Stack->base; Stack->max = Stack->base + init_element_num; return Stack_OK; }
bool Stack_new(struct my_Stack* Stack, ll num) { Stack->base = (Elemtype *)realloc(Stack->base,sizeof(Elemtype) * num); if(Stack->base == NULL) { return false; } Stack->stack_size = num; Stack->max = Stack->base + num; return Stack_OK; }
ll Stack_get_len(struct my_Stack* Stack) { return Stack->stack_size; }
bool Stack_empty(struct my_Stack* Stack) { if(Stack->top == Stack->base) { return true; } else { return false; } }
bool Stack_full(struct my_Stack* Stack) { if(Stack->top == Stack->max) { return true; } else { return false; } }
void Stack_clear(struct my_Stack* Stack) { Stack->top = Stack->base; return ; }
bool Push(struct my_Stack* Stack, Elemtype ele) { if(Stack_full(Stack) == true) { if(Stack_new(Stack,Stack->stack_size * 2) == false) { return false; } } *Stack->top = ele; Stack->top++; return Stack_OK; }
Elemtype Pop(struct my_Stack* Stack) { if(Stack_empty(Stack) == true) { printf("弹栈失败:这个栈已经是空的了.\n"); return ~(unsigned int)0/2; } else { Stack->top--; return *Stack->top; } }
bool Stack_destory(struct my_Stack* Stack) { Stack->top = Stack->base; free(Stack->base); Stack->stack_size = 0; return Stack_OK; }
|
calc.h
calc.h1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #ifndef _calc_H_ #define _calc_H_
#include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include "My_Stack.h" #include "func_calc.h"
#define cal_max_idx 100
#define details #define details_Stack #define details_array
struct ele { char *p_opt; double *p_num; };
double calc(char *str);
#endif
|
func_calc.h
func_calc.h1 2 3 4 5 6
| #ifndef _Func_calc_H_ #define _Func_calc_H_
char* str_find_exp_and_calc(char *s);
#endif
|
func_calc.c
func_calc.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
| #include <stdio.h> #include <string.h> #include <stdlib.h> #include <math.h> #include "func_calc.h" #include "calc.h"
char *str_rpl(char *s, const char *s1, const char *s2) { char *ptr; while ((ptr = strstr(s, s1)) != NULL) { memmove(ptr + strlen(s2) , ptr + strlen(s1), strlen(ptr) - strlen(s1) + 1); memcpy(ptr, &s2[0], strlen(s2)); } return s; }
void str_reverse(char* s) { char* left = s; char* right = s + strlen(s) - 1; while (left < right) { char tmp = *left; *left = *right; *right = tmp;
left++; right--; } }
char* double2str(double num) { static char str[21]; sprintf(str, "%lf", num); return str; }
double str2double(const char* str) { return atof(str); }
typedef double (*math_fun)(double); math_fun get_math_fun(const char *s) { if (strcmp(s, "sin") == 0) { return sin; } else if (strcmp(s, "cos") == 0) { return cos; } else if (strcmp(s, "tan") == 0) { return tan; } else if (strcmp(s, "sinh") == 0) { return sinh; } else if (strcmp(s, "cosh") == 0) { return cosh; } else if (strcmp(s, "tanh") == 0) { return tanh; } else if (strcmp(s, "asin") == 0) { return asin; } else if (strcmp(s, "acos") == 0) { return acos; } else if (strcmp(s, "atan") == 0) { return atan; } else if (strcmp(s, "exp") == 0) { return exp; } else if (strcmp(s, "log") == 0) { return log; } else if (strcmp(s, "log10") == 0) { return log10; } else if (strcmp(s, "sqrt") == 0) { return sqrt; } else if (strcmp(s, "ceil") == 0) { return ceil; } else if (strcmp(s, "floor") == 0) { return floor; } else { return NULL; } }
typedef struct { int exp_count; char **exp_funcs; char **exp_strs; char **exp_results; }exp_strStuctTypedef;
char* str_find_exp_and_calc(char *s) { char *ptr = s;
char exp_func[100] = {0}; int exp_func_i = 0; char **exp_funcs = (char **)malloc(sizeof(char *) * 100); int exp_funcs_i = 0; memset(exp_funcs, 0, sizeof(char *) * 100);
char exp_str[100] = {0}; int exp_str_i = 0; char **exp_strs = (char **)malloc(sizeof(char *) * 100); int exp_strs_i = 0; memset(exp_strs, 0, sizeof(char *) * 100);
char **exp_results = (char **)malloc(sizeof(char *) * 100);
while (*ptr++) { if ((*ptr == '(') && (*(ptr - 1) != '(') && (*(ptr - 1) != '+') && (*(ptr - 1) != '-') && (*(ptr - 1) != '*') && (*(ptr - 1) != '/')) { char *exp_func_ptr = ptr; while(*exp_func_ptr--) { if((*exp_func_ptr != '+') && (*exp_func_ptr != '-') && (*exp_func_ptr != '*') && (*exp_func_ptr != '/') && (*exp_func_ptr != '(')) { exp_func[exp_func_i++] = *exp_func_ptr; } else { exp_func[exp_func_i] = '\0'; exp_funcs[exp_funcs_i] = (char *)malloc(sizeof(char) * (exp_func_i + 1));
strcpy(exp_funcs[exp_funcs_i], exp_func); str_reverse(exp_funcs[exp_funcs_i]); exp_funcs_i++; memset(exp_func, 0, 100); exp_func_i = 0;
break; } }
int count_kuohao = -1; char *sub_str_ptr = ptr + 1; memset(exp_str, 0, 100);
do { if(*sub_str_ptr == ')') { count_kuohao++; } else if(*sub_str_ptr == '(') { count_kuohao--; }
if(count_kuohao != 0) { exp_str[exp_str_i++] = *sub_str_ptr; } else { exp_str[exp_str_i] = '\0'; exp_strs[exp_strs_i] = (char *)malloc(sizeof(char) * (exp_str_i + 1));
strcpy(exp_strs[exp_strs_i], exp_str); exp_strs_i++; memset(exp_str, 0, 100); exp_str_i = 0; break; }
}while(*sub_str_ptr++); } }
for (int i = 0; i < exp_strs_i; i++) { char str_temp[100] = {0}; strcpy(str_temp, exp_strs[i]); double temp = calc(exp_strs[i]); strcpy(exp_strs[i], str_temp);
char *temp_result_str = double2str(get_math_fun(exp_funcs[i])(temp)); exp_results[i] = (char *)malloc(sizeof(char) * (strlen(temp_result_str) + 1)); strcpy(exp_results[i], temp_result_str); }
exp_strStuctTypedef exp_strStuct; exp_strStuct.exp_count = exp_strs_i; exp_strStuct.exp_funcs = exp_funcs; exp_strStuct.exp_strs = exp_strs; exp_strStuct.exp_results = exp_results;
for (int i = 0; i < exp_strStuct.exp_count; i++) { char temp[100] = {0}; strcpy(temp, exp_strStuct.exp_funcs[i]); strcat(temp, "("); strcat(temp, exp_strStuct.exp_strs[i]); strcat(temp, ")"); if(exp_strStuct.exp_results[i][0] == '-') { char *temp = exp_strStuct.exp_results[i]; exp_strStuct.exp_results[i] = (char *)malloc(sizeof(char) * (strlen(exp_strStuct.exp_results[i]) + 3)); memset(exp_strStuct.exp_results[i], 0, sizeof(char) * (strlen(exp_strStuct.exp_results[i]) + 3));
exp_strStuct.exp_results[i][0] = '('; exp_strStuct.exp_results[i][1] = '0'; strcpy(exp_strStuct.exp_results[i] + 2, temp); exp_strStuct.exp_results[i][strlen(exp_strStuct.exp_results[i])] = ')';
free(temp); } str_rpl(s, temp, exp_strStuct.exp_results[i]);
}
return s; }
|
calc.c
calc.c1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
| #include <stdio.h> #include <string.h> #include <math.h> #include <stdlib.h> #include "My_Stack.h" #include "func_calc.h" #include "calc.h"
int Priority(char ch) { switch(ch) { case '^': return 3; case '*': case '/': return 2; case '+': case '-': return 1; default: return 0; } }
bool mid_to_back(char *str, ll len, struct ele result[]) { ll i; ll count_num = 1; ll count_opt = 0; char *p; double num[100] = {0}; char opt[100] = {'\0'}; long opt_idx[100] = {0};
ll count_num_idx = 0; ll count_opt_idx = 0; struct ele infix_expression[100];
for (i = 0; i < sizeof(opt_idx)/sizeof(opt_idx[0]); ++i) { opt_idx[i] = -1; } for(i = 0; i < 100; ++i) { infix_expression[i].p_num = NULL; infix_expression[i].p_opt = NULL; }
for(i = 0 ; i < len ; ++i) { if(str[i] == '[' || str[i] == '{') { str[i] = '('; } else if(str[i] == ']' || str[i] == '}') { str[i] = ')'; }
if(str[i] == '+' || str[i] == '-' || str[i] == '*' || str[i] == '/' || str[i] == '^' || str[i] == '(' || str[i] == ')') { opt[count_opt] = str[i]; opt_idx[i] = 1; count_opt++; } else { opt_idx[i] = 0; } }
for(int i = 0; i < 99; ++i) { if(opt_idx[i] == 0 && opt_idx[i+1] == 0) { for(int j = i; j < 99; ++j) { opt_idx[j] = opt_idx[j+1]; } i--; } } ll max_idx = 0; for(i = 0 ; i < 100 ; ++i) { if(opt_idx[i] == -1) { max_idx = i; break; } }
p = strtok(str, "+-*/^()"); num[0] = atof(p); while((p = strtok(NULL, "+-*/^()"))) { num[count_num++] = atof(p); } #ifdef details printf("获取所有的浮点数:\n"); for (i = 0; i < count_num; ++i) { printf("%f ",num[i]); } putchar('\n'); printf("\n获取所有的运算符:\n"); for (i = 0; i < strlen(opt); ++i) { printf("%c ",opt[i]); } putchar('\n'); putchar('\n'); #endif
for (i = 0; i < max_idx; ++i) { if(opt_idx[i] == 1) { infix_expression[i].p_num = NULL; infix_expression[i].p_opt = &opt[count_opt_idx]; count_opt_idx++; } else if(opt_idx[i] == 0) { infix_expression[i].p_num = &num[count_num_idx]; infix_expression[i].p_opt = NULL; count_num_idx++; } }
#ifdef details printf("转换完的中缀表达式如下:\n"); for (i = 0; i < max_idx; ++i) { if(infix_expression[i].p_num != NULL) { printf("%lf ",*infix_expression[i].p_num); } if(infix_expression[i].p_opt != NULL) { printf("%c ",*infix_expression[i].p_opt); } } putchar('\n'); #endif #ifdef details_Stack printf("\n开始转换后缀表达式:\n"); #endif struct my_Stack Stack_calculate; struct ele postfix_Expression[100]; ll count_postfix_idx = 0; Stack_init(&Stack_calculate); char opt_cal; ll opt_temp_idx = 0; char opt_temp[100]; char opt_top; for(i = 0; i < 100; ++i) { postfix_Expression[i].p_num = NULL; postfix_Expression[i].p_opt = NULL; }
for (i = 0; i < max_idx; ++i) { if(infix_expression[i].p_num != NULL) { postfix_Expression[count_postfix_idx] = infix_expression[i]; count_postfix_idx++; } else if(infix_expression[i].p_opt != NULL) { opt_cal = *infix_expression[i].p_opt; if( opt_cal == '(') { Push(&Stack_calculate,opt_cal); #ifdef details_Stack printf("符号: %c 入栈\n",opt_cal); #endif continue; } if( opt_cal != ')') { if(Stack_empty(&Stack_calculate) == true) { opt_top = ' '; } else { opt_top = *(Stack_calculate.top-1); #ifdef details_Stack printf("符号: %c 出来作比较\n",opt_top); #endif } if(Priority(opt_cal) > Priority(opt_top)) { Push(&Stack_calculate,opt_cal); #ifdef details_Stack printf("符号: %c 入栈\n",opt_cal); #endif } else { while(Priority(opt_cal) <= Priority(opt_top)) { if(Stack_empty(&Stack_calculate) == true || *(Stack_calculate.top-1) == '(') { break; } opt_top = Pop(&Stack_calculate); #ifdef details_Stack printf("符号: %c 弹栈\n",opt_top); #endif opt_temp[opt_temp_idx] = opt_top; postfix_Expression[count_postfix_idx].p_opt = &opt_temp[opt_temp_idx]; postfix_Expression[count_postfix_idx].p_num = NULL; count_postfix_idx++; opt_temp_idx++; } Push(&Stack_calculate,opt_cal); #ifdef details_Stack printf("符号: %c 入栈\n",opt_cal); #endif } } else { #ifdef details_Stack printf("右括号来了\n"); #endif char char_tmp = 0; while(char_tmp != '(') { char_tmp = Pop(&Stack_calculate); #ifdef details_Stack printf("符号: %c 弹栈\n",char_tmp); #endif if(char_tmp == '(') { break; } opt_temp[opt_temp_idx] = char_tmp; postfix_Expression[count_postfix_idx].p_opt = &opt_temp[opt_temp_idx]; postfix_Expression[count_postfix_idx].p_num = NULL; opt_temp_idx++; count_postfix_idx++; } } } } while(Stack_empty(&Stack_calculate) == false) { opt_top = Pop(&Stack_calculate); #ifdef details_Stack printf("符号: %c 弹栈\n",opt_top); #endif opt_temp[opt_temp_idx] = opt_top; postfix_Expression[count_postfix_idx].p_opt = &opt_temp[opt_temp_idx]; postfix_Expression[count_postfix_idx].p_num = NULL; opt_temp_idx++; count_postfix_idx++; }
for (i = 0; i < max_idx; ++i) { result[i].p_num = postfix_Expression[i].p_num; result[i].p_opt = postfix_Expression[i].p_opt; } #ifdef details printf("\n转换的后缀表达式如下:\n"); for (i = 0; i < max_idx; ++i) { if(postfix_Expression[i].p_num != NULL) { printf("%lf ",*postfix_Expression[i].p_num); continue; } else if(postfix_Expression[i].p_opt != NULL) { printf("%c ",*postfix_Expression[i].p_opt); continue; } } putchar('\n'); #endif Stack_clear(&Stack_calculate); Stack_destory(&Stack_calculate); return true; }
double caculate_four_arithmetic_operations(struct ele* postfix_Expression) { struct my_Stack Stack_calculate; Stack_init(&Stack_calculate); double *num_tmp = (double*)malloc(sizeof(double)*100); ll count = 0; for(int i = 0; i < 100; ++i) { if(postfix_Expression[i].p_num != NULL) { num_tmp[count] = *postfix_Expression[i].p_num; count++; } } #ifdef details_Stack printf("\n接下来开始用栈计算最终的结果\n"); #endif ll max_idx = count; ll max_idx_count = 0;
count = 0; for (int i = 0; i < 100; ++i) { if(postfix_Expression[i].p_num != NULL) { Push(&Stack_calculate,count); #ifdef details_Stack printf("下标: [%ld]=%lf 入栈\n",count,num_tmp[count]); #endif count++; continue; } if(postfix_Expression[i].p_opt != NULL) { ll num_1_idx = Pop(&Stack_calculate); ll num_2_idx = Pop(&Stack_calculate); #ifdef details_Stack printf("下标: [%ld]=%lf & [%ld]=%lf 弹栈\n",num_1_idx,num_tmp[num_1_idx],num_2_idx,num_tmp[num_2_idx]); #endif switch (*postfix_Expression[i].p_opt) { case '^': { num_tmp[max_idx+max_idx_count] = pow(num_tmp[num_2_idx],num_tmp[num_1_idx]); Push(&Stack_calculate,max_idx+max_idx_count); #ifdef details_Stack printf("下标: [%ld]=%lf 入栈\n",max_idx+max_idx_count,num_tmp[max_idx+max_idx_count]); #endif max_idx_count++; break; } case '+': { num_tmp[max_idx+max_idx_count] = num_tmp[num_2_idx] + num_tmp[num_1_idx]; Push(&Stack_calculate,max_idx+max_idx_count); #ifdef details_Stack printf("下标: [%ld]=%lf 入栈\n",max_idx+max_idx_count,num_tmp[max_idx+max_idx_count]); #endif max_idx_count++; break; } case '-': { num_tmp[max_idx+max_idx_count] = num_tmp[num_2_idx] - num_tmp[num_1_idx]; Push(&Stack_calculate,max_idx+max_idx_count); #ifdef details_Stack printf("下标: [%ld]=%lf 入栈\n",max_idx+max_idx_count,num_tmp[max_idx+max_idx_count]); #endif max_idx_count++; break; } case '*': { num_tmp[max_idx+max_idx_count] = num_tmp[num_2_idx] * num_tmp[num_1_idx]; Push(&Stack_calculate,max_idx+max_idx_count); #ifdef details_Stack printf("下标: [%ld]=%lf 入栈\n",max_idx+max_idx_count,num_tmp[max_idx+max_idx_count]); #endif max_idx_count++; break; } case '/': { num_tmp[max_idx+max_idx_count] = num_tmp[num_2_idx] / num_tmp[num_1_idx]; Push(&Stack_calculate,max_idx+max_idx_count); #ifdef details_Stack printf("下标: [%ld]=%lf 入栈\n",max_idx+max_idx_count,num_tmp[max_idx+max_idx_count]); #endif max_idx_count++; break; } default: break; } continue; } } double result = num_tmp[Pop(&Stack_calculate)]; Stack_destory(&Stack_calculate); free(num_tmp); return result; }
double calc(char *str) { double result = 0; struct ele postfix_Expression[100]; memset(postfix_Expression, 0, sizeof(postfix_Expression));
char new_str[100]; memset(new_str, 0, sizeof(new_str)); new_str[0] = '0'; new_str[1] = '+'; strcpy(new_str+2, str);
for (int i = 0; i < sizeof(new_str); i++) { if(new_str[i] == '[' || new_str[i] == '{') { new_str[i] = '('; } else if(new_str[i]== ']' || new_str[i] == '}') { new_str[i] = ')'; } }
str_find_exp_and_calc(new_str); printf("str_find_exp_and_calc : %s\n", new_str);
mid_to_back(new_str, strlen(new_str), postfix_Expression); result = caculate_four_arithmetic_operations(postfix_Expression);
return result; }
|