一个简单的四则运算程序C语言实现--实现处理括号

 

说明:经过今天的测试解决了括号处理的一些问题。比如由于增加了paren 结构元素之后,复制函数没有更新。

及非直接括号。等类型。如(2+4)等非必须性括号。

没有使用高级的数据结构如堆栈啦。

但程序本还是挺好的。注释也挺 不错。

写得也不错。 哈哈。两天的成果啊!完全自己写的啊!

/*** * @author banxi1988 * @mail banxi1988 at gmail.com * @qq 787928000 * 一个简单的表达式四则运算器。C语言实现。实现处理括号。 * @bug-report : if have any suggestion and find any bug please send mail to my mail or send massage to my qq! thanks */ #include #include #include #include //#define BANXI_DEBUG 1 // 是否为调试模式 #define MAX_LEN 1024 //最长的运算表达式。 #define D_BIT_LEN 32 //最大数值位包括小数点。 /*** * 一些有用的宏,关于字符操作 */ #define is_numerical(ch) (strchr("0123456789.",(ch)) != NULL) // 决断是否是组成数值的元素 #define is_operator(ch) (strchr("+-*/",(ch)) != NULL) // 判断是否是运算符 #define is_muldiv(ch) (strchr("*/",(ch)) != NULL) // 判断是否是乘法或除法 #define is_paren(ch) (strchr("()",(ch)) != NULL) //判断是否是括号 #define is_end_input(ch) (ch == EOF || ch == '/n') //判断是否是输入的结尾。一次只允许输入一行。所以.. typedef enum OP_TYPE_TAG{OPERAND,OPERATOR,LPAREN,RPAREN}OP_TYPE; // 表达式元素类型,lparen 意为左括号。rparen意为右括号 typedef struct OP_ITEM_TAG{ // 表达式元素项类型 double operand; // 用来存储操作数 char operator; // 存储操作符 char paren; // 存储括号 OP_TYPE op_type; // 存储元素类型 }OP_ITEM; OP_ITEM op_items[MAX_LEN] = {{0,0,0,0}};// 表达式元素项数组。 int items_count = 0; // 元素项数 int operand_count = 0; // 操作数数 int operator_count = 0;// 操作符数 int lparen_count = 0; //左括号数 int rparen_count = 0; //右括号数 /*** * @function: 移除表达式元素之间空白符。 * 因为'/n'也是空白符。一般输入当中也容易把作为输入结束标志。 * 所以。如果处理'/n'当作结束标志。 */ int remove_space(){ char ch; while(isspace(ch=getchar())&&(!is_end_input(ch))); ungetc(ch,stdin); }//end remove_space /*** * @function: 如果输入的表达式操作数位数过大,进行提示。 * 虽然double型数据可以达到正负37位。但是此程序只处理32位。 * 所以提示。因为小程序,不想处理那么大的数值 */ int bits_length_tips(int index){ if(index > 37){ printf("WARNING:YOU HAVE INPUT A TOO LARGER NUMBER,IF HAVE NO POINT!/n"); }else if(index > D_BIT_LEN){ printf("WARNING:YOU HAVA INPUT A LARGER NUMBER!/n"); }// }//end bits_length_tips /*** * @function: 扫描标准输入。组建表达式。并判断是否是有效的运算表达式。 * 此函数比较关键。逻辑相当复杂点。经过重构之后,显得稍微清楚了点。 * 合理利用库函数。是一大亮点。 */ int scan_input(){ char buffer[D_BIT_LEN] = {'/0'}; char operator = 'a'; double operand = 0.0; char ch = 'a'; OP_TYPE op_type; int index = 0; //for digit bit count int flag = 0; //for float . token count int fail = 0; while(1){ remove_space(); ch = getchar(); if(is_end_input(ch)){ break; }//end end if if(is_numerical(ch)){ /// 接受到非数字组成字符跳出,或者空格也跳出 index = 0; do{ if(isdigit(ch)){ buffer[index++] = ch; }else{ flag++; if(flag > 1){ printf("ERROR:too many /'./' char,need a number/n"); exit(EXIT_FAILURE); }else{ buffer[index++] = ch; } }// }while(is_numerical(ch=getchar()));//end numerical while ungetc(ch,stdin);// 将空格或者其它字符放回,以便下面处理 bits_length_tips(index); // 超多位数可能越界提示 index = (index > 36)?36:index; buffer[index] = '/0'; operand = atof(buffer); op_items[items_count].operand = operand; op_items[items_count].op_type = OPERAND; operand_count++; items_count++; }else if(is_operator(ch)){ op_items[items_count].operator = ch; op_items[items_count].op_type = OPERATOR; operator_count++; items_count++; }else if(is_paren(ch)){ op_items[items_count].paren = ch; // op_type = (ch == '(')?LPAREN:RPAREN; if(ch == '('){ op_type = LPAREN; lparen_count++; }else{ op_type = RPAREN; rparen_count++; } op_items[items_count].op_type = op_type; items_count++; }else{ printf("ERROR:NON VALID CHAR %c/n",ch); exit(EXIT_FAILURE); }//end ch judge }//end scan while if(items_count % 2 == 0){ printf("ERROR:non valid expression/n"); fail = 1; }// if(lparen_count != rparen_count){ printf("ERROR:PARENTHESIS NOT MATCH!/n"); fail = 1; }// if(operand_count != (operator_count + 1)){ printf("ERROR:OPERAND OR OPERATOR NOT ENOUGH/n"); fail = 1; }// if(fail){ exit(EXIT_FAILURE); }// return 0; }// end scan_input /*** * @function:用于调试时打印op_items中的数据项。 */ void print_data(){ int i = 0; for(i = 0; i < items_count; i++){ if(op_items[i].op_type == OPERAND){ printf("%d/t%lf/t",i,op_items[i].operand); }// else if(op_items[i].op_type == OPERATOR){ printf("%d/t%c/t",i,op_items[i].operator); }else{ printf("%d/t%c/t",i,op_items[i].paren); }// printf("/n"); }//end for }//end print_data /*** * @function :根据传入的两个数及运算符即操作符,返回运算结果 * @return : double * 说明:均为从左到右运算 */ double cal(double left,char op,double right){ switch(op){ case '+':return left+right;break; case '-':return left - right ;break; case '*':return left*right;break; case '/': if(right == 0){ printf("divide not be 0/n");exit(EXIT_FAILURE); }// else{ return left/right; } break; default: printf("non valid operator %c /n",op); exit(EXIT_FAILURE); break; }//end op switch }//end cal /** * @function :将下标from处的op_items内容复制到dest下标处。dest处的内容将被覆盖。 */ void copy_items(int dest,int from){ op_items[dest].operand = op_items[from].operand; op_items[dest].operator = op_items[from].operator; op_items[dest].paren = op_items[from].paren; op_items[dest].op_type = op_items[from].op_type; }//end copy_items /** * @function: 从start下标处开始。将steps后的op_items中的内容往前移steps个单位。 * 即start后面的steps个数组内容没有了将后面的向前移动以便对齐。 * */ int move_items(int start,int steps){ int index = 0; for(index = start ; (index+steps) < items_count; index++){ copy_items(index,index+steps); }// return 0; }//end move_items /*** * @fuction: 按顺序查找操作符的在op_items中的下标。 * 依赖items_count */ int find_operator(){ int i = -1; int end = items_count -1; for(i = 1; i < end; i++){ if(op_items[i].op_type == OPERATOR){ return i; }//END IF }//end for return -1; }// /** * @function : 扫描op_items数组,查找乘法或者除法。如果返回找到第一个的下标。 * 如果没有找到返回-1 */ int find_muldiv(){ int i = 0; int end = items_count -1; for(i = 1; i < end; i++){ if(op_items[i].op_type == OPERATOR){ if(is_muldiv(op_items[i].operator)){ return i; }//end }//end op_type if }// return -1; }// /*** * @function :查找最里面的左括号。如果找到返回相应op_items下标。否则返回-1 * */ int find_inner_lparen(){ int innerest = -1; int i = 0; int end = items_count - 1; for(i = 0; i < end; i++){ if(op_items[i].op_type == LPAREN){ innerest = i; }// }//end i for return innerest; }// /*** * @function :查找最里面的左括号。如果找到返回相应op_items下标。否则返回-1 * */ int find_inner_rparen(){ int i = 0; int end = items_count - 1; for(i = 0; i < end; i++){ if(op_items[i].op_type == RPAREN){ return i; }// }//end i for return -1; }// /*** * @function : 带优先级的表达式计算。括号,最优,乘除次之。接着加减。 * 一种思路就是,先扫描整个op_items 数组。找到优先级最高的计算。 * 然后将后面前移。 */ double cal_exp_with_pri(){ int index = 0; int rparen_index = 0; int i = 0; int op_index = 0; // 操作符下标 int result_index = 0;// 运算结果存储位置下标。 int steps = 0; // 前移项数 int end = 0; double result = 0; op_index = 0; end = operator_count + 1; //因为把计算部分统一移到了for的开头。所以要多一次循环。 for(i = 0; i < end; i++){ if(op_index > 0){ result = cal(op_items[op_index - 1].operand,op_items[op_index].operator,op_items[op_index+1].operand); op_items[result_index].operand = result; op_items[result_index].op_type = OPERAND; move_items(result_index+1,steps); items_count -= steps; #ifdef BANXI_DEBUG printf("/n=====CURRENT OP_ITEMS=============================/n"); print_data(); #endif }//end index = find_inner_lparen(); rparen_index = find_inner_rparen(); // 处理外围大括号情况。 if((index > -1) && (rparen_index - index)== 4){ op_index = index + 2; result_index = index; steps = 4; continue; // }//end if index = find_muldiv(); if(index > 0){ op_index = index; result_index = index -1; steps = 2; continue; // }// index = find_operator(); // 执行到这里说明已经没有括号,乘除了。返回的是加减法操作符。 if(index > 0){ op_index = index; result_index = index -1; steps = 2; continue; }//end if }//end operator_count for if(items_count > 2)return op_items[1].operand; // 出现外围的括号无法依靠上面的处理完全消除(12) 这样的情况 return op_items[0].operand; }//end int main(void){ double result = 0.0; scan_input(); #ifdef BANXI_DEBUG printf("/n=======CURRENT OP_ITEMS================================/n"); print_data(); #endif // BANXI_DEBUG result = cal_exp_with_pri(); printf("/t %.2lf/n",result); printf("calculate takes time %ld seconds /n",clock()/CLOCKS_PER_SEC); return EXIT_SUCCESS; }//end /***** 运行及测试结果: 调试模式输出如下: banxi1988@banxi:~/cpp/c/exp_cal$ gcc -g -o simple simple.c banxi1988@banxi:~/cpp/c/exp_cal$ ls exp_calSession.vim simple01.c simple.c test_simple.txt simple simple01_with_pri.c simple_with_pri.c banxi1988@banxi:~/cpp/c/exp_cal$ vi test_simple.txt banxi1988@banxi:~/cpp/c/exp_cal$ cat test_simple.txt | ./simple 0 ( 1 ( 2 2.000000 3 + 4 1.000000 5 ) 6 * 7 3.000000 8 + 9 3.000000 10 ) 0 ( 1 3.000000 2 * 3 3.000000 4 + 5 3.000000 6 ) ============================================================== 0 ( 1 9.000000 2 + 3 3.000000 4 ) ============================================================== 0 ( 1 12.000000 2 ) ============================================================== 0.00 calculate takes time 0 seconds banxi1988@banxi:~/cpp/c/exp_cal$ gcc -g -o simple simple.c banxi1988@banxi:~/cpp/c/exp_cal$ cat test_simple.txt | ./simple ===== CURRENT OP_ITEMS ==================================== 0 ( 1 ( 2 2.000000 3 + 4 1.000000 5 ) 6 * 7 3.000000 8 + 9 3.000000 10 ) ===== CURRENT OP_ITEMS ==================================== 0 ( 1 3.000000 2 * 3 3.000000 4 + 5 3.000000 6 ) ===== CURRENT OP_ITEMS ==================================== 0 ( 1 9.000000 2 + 3 3.000000 4 ) ===== CURRENT OP_ITEMS ==================================== 0 ( 1 12.000000 2 ) 12.00 calculate takes time 0 seconds banxi1988@banxi:~/cpp/c/exp_cal$ gcc -g -o simple simple.c banxi1988@banxi:~/cpp/c/exp_cal$ cat test_simple.txt ((2+1)*3+3) banxi1988@banxi:~/cpp/c/exp_cal$ cat test_simple.txt | ./simple =======CURRENT OP_ITEMS================================ 0 ( 1 ( 2 2.000000 3 + 4 1.000000 5 ) 6 * 7 3.000000 8 + 9 3.000000 10 ) =====CURRENT OP_ITEMS============================= 0 ( 1 3.000000 2 * 3 3.000000 4 + 5 3.000000 6 ) =====CURRENT OP_ITEMS============================= 0 ( 1 9.000000 2 + 3 3.000000 4 ) =====CURRENT OP_ITEMS============================= 0 ( 1 12.000000 2 ) 12.00 calculate takes time 0 seconds banxi1988@banxi:~/cpp/c/exp_cal$ gcc -g -o simple simple.c banxi1988@banxi:~/cpp/c/exp_cal$ cat test_simple.txt | ./simple 12.00 calculate takes time 0 seconds banxi1988@banxi:~/cpp/c/exp_cal$ * */  

你可能感兴趣的:(一个简单的四则运算程序C语言实现--实现处理括号)