C语言计算器详细教程(四则运算、小数、括号)


前言

最近做嵌入式设备开发刚好需要用到对数据的公式处理,写了一个四则运算器,顺便分享给有需要各位


提示:以下为正文内容

目标功能

假设有如下参数:

	float	value 		= 5 ;
	char*	formula 	= " 1 * 2 / 3 + 4 / x + 6 " ;

实现将设备采集的数值替换公式中的字符 ’ x ’ ,并计算出结果。这里封装了两个工具函数来实现此需求,第一个公式用于将数值 value 代入公式中的字符 ’ x ',第二个公式用于计算四则运算式。

	/* 
	 *  功能:	字符串的指定内容替换
	 *  参数:	
	 * 			str	    目标字符串
	 * 			oldstr  被替换的字符串
	 *          newstr  替换的字符串
	 */
	char *Utils_Strrpc(char *str, char *oldstr, char *newstr) ;
	
	/* 
	 *  功能:	四则运算
	 *  参数:	
	 * 			formula	运算公式
	 *   		length	公式长度
	 */
	CALCULATERESULT utils_Calculate(char* formula, int length) ;

四则运算函数返回的结构体如下:

	/* 
	 *  内容:	四则运算结果 
	 * 	目标函数:	
	 * 			utils_Calculate
	 */
	typedef struct CALCULATERESULTSTRUCT {
	    int 	err;	// 格式错误码
	    float 	value;	// 运算值
	    
	} CALCULATERESULT;

不带括号的公式处理

我们先以不带括号的公式为例,有公式如下:

	char* formula = " 1 * 2 / 3 + 4 / 5 + 6 " ;

第一步,我们建立两个数组,分别存储数字和运算符:

	digits		=	{ 1   2   3   4   5   6 } 
	operators	=	{   *   /   -   /   +   } 

四则运算第一个要处理的问题就是 “加减” 与 ”乘除“ 运算符的执行先后问题,我们来看下面两组式子:

	   	_1 	= 	" 1 + 2 * 3 " ;
	// 	_2 	= 	" 1 + 0 ? 6 " ;
	   	_2 	= 	" 1 + 0 + 6 " ;
	
		_3 	= 	" 1 - 6 / 2 " ;
	//	_4 	= 	" 1 - 0 ? 3 " ;
		_4 	= 	" 1 - 0 - 3 " ;

不难看出1和2、3和4两组式子的结果是相同的。所以在这里,我们解决问题的方法是:

	将 ”乘除“ 运算符的左值变为0,将右值变为左右两值"乘除"运算的结果;
	将 "乘除" 运算符变为左边第一个"加减"运算符,如为公式的第一个运算符,则为默认为'+';

紧接着示例公式,我们处理如下:

	digits 		{ 1   2   3   4   5   6 }
	operators	{   *   /   -   /   +   }
--------------------------------------------------------------
	digits 		{ 0   2   3   4   5   6 }
	operators	{   ?   /   -   /   +   }
--------------------------------------------------------------
	digits 		{ 0   0   6   4   5   6 }
	operators	{   ?   ?   -   /   +   }
--------------------------------------------------------------
	digits 		{ 0   0   6   0   20  6 }
	operators	{   ?   ?   -   ?   +   }
--------------------------------------------------------------
	digits 		{ 0   0   6   0   20  6 }
	operators	{   ?   ?   -   ?   +   }
--------------------------------------------------------------
	digits 		{ 0   0   6   0   20  6 }
	operators	{   +   +   -   -   +   }

第二步,我们定义一个结果值 value,让结果值等于digits[ 0 ],并根据符号依次加减运算digits[ 1 ] 到 digits [ n ],最后value的值就是我们公式处理的结果值,紧接着示例公式,我们处理如下:

	value  	= 	digits[0]
	  0			   0
-----------------------------------------------------
	value 	operators[0]	digits[1] 
	  0         +			   0		=		0
-----------------------------------------------------
	value 	operators[1]	digits[2] 
	  0         +			   6		=		6
-----------------------------------------------------
	value 	operators[2]	digits[3] 
	  6         -			   0		=		6
-----------------------------------------------------
	value 	operators[3]	digits[4] 
	  6         -			   20		=		-20
-----------------------------------------------------
	value 	operators[4]	digits[5] 
	  -20       +			   6		=		-16

带括号的公式处理

四则运算第二个需要处理的问题就是括号带来的运算优先级问题,这里我们使用递归的方式处理,有公式如下:

	char 	*formula 	= " 1 * ( 2 + ( 3 + 4 ) / 5 + 6 ) " ;

因为有两层括号,实际程序执行时会执行两次递归。我们建立两个数组,分别存储数字和运算符,函数执行递归情况如下:

----------------------------------------------------- // 开始层函数的数组
	digits 		{ 1   ? }
	operators	{   *   }
----------------------------------------------------- // 第一层递归函数的数组
	digits 		{ 2   ?   5   6}
	operators	{   +   /   +  }
----------------------------------------------------- // 第二层递归函数的数组
	digits 		{ 3   4}
	operators	{   +  }
-----------------------------------------------------

第二层递归函数按照 “不带括号的公式处理” 执行完后,返回的计算结果 ’ 7 ’ 替代第一层递归函数素组digits中 ’ ? ’ 位的值,得到如下:

----------------------------------------------------- // 第一层递归函数的数组
	digits 		{ 1   ? }
	operators	{   *   }
----------------------------------------------------- // 第二层递归函数的数组
	digits 		{ 2   7   5   6}
	operators	{   +   /   +  }

同理,执行第三层函数,得到如下:

----------------------------------------------------- // 第一层递归函数的数组
	digits 		{ 1   9.4 }
	operators	{   *   }

最后即可得出结果为10.4。

源码

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

#define CALCULATE_ERR_REPEAT    -1  // 重复运算符
#define CALCULATE_ERR_SYMBOL    -2  // 非法字符
#define CALCULATE_ERR_NUMBER    -3  // 数字与运算符数量不对应
#define CALCULATE_ERR_BEYOND    -4  // 数字数量,运算符数量,数字长度超出预设值


#define CALCULATE_MAX_DIGITS    30  // 限制数字最大数量
#define CALCULATE_MAX_OPERATOR  30  // 限制运算符最大数量
#define CALCULATE_MAX_DIGIT     30  // 限制数字最大位数

/* 
 *  内容:	运算结果 
 * 	函数:	utils_Calculate
 */
typedef struct CALCULATERESULTSTRUCT {
    int err;
    float value;

} CALCULATERESULT;

/* 
 *  功能:	字符串指定内容替换
 *  参数:	
 * 			str	    目标字符串
 * 			oldstr  被替换的字符串
 *          newstr  替换的字符串
 */
char *Utils_Strrpc(char *str, char *oldstr, char *newstr)
{
    char bstr[strlen(str)];

    memset(bstr, 0, sizeof(bstr));

    int i;

    for (i = 0; i < strlen(str); i++) {

        if (!strncmp(str + i, oldstr, strlen(oldstr))) {
        
            strcat(bstr, newstr);
            i += strlen(oldstr) - 1;
        
        } else {
        
            strncat(bstr, str + i, 1);
        }
    }

    strcpy(str, bstr);

    return str;
}

/* 
 *  功能:	实时数据四则运算处理
 *  参数:	
 * 			formula	运算公式
 * 			length	公式长度
 */
CALCULATERESULT Utils_Calculate(char* formula, int length)
{
    CALCULATERESULT result = {0, 0.0f};         // 返回结构体
    int idx;                                    // 索引

    int digitsNum = 0;                          // 数字数量
    float digits[CALCULATE_MAX_DIGITS];         // 存储数据的数组
    memset(digits, '\0', sizeof(digits));

    int optNum = 0;                             // 运算符数量
    char operator[CALCULATE_MAX_OPERATOR];      // 存储运算符的数组
    memset(operator, '\0', sizeof(operator));

    int digitNum = 0;                           // 单个数字字符串
    char digit[CALCULATE_MAX_DIGIT];            // 存储单个数字字符串的数组
    memset(digit, '\0', sizeof(digit));

    /* 提取数字和符号到数组 */

    char *pointer = formula;

    while (length--)
    {
        switch(*pointer) {

        case '+':
        case '-':
        case '*':
        case '/':

           if (0 == digitNum && '-' == *pointer) {

                digit[digitNum++] = *pointer;

            } else {

	            if (-1 == digitNum) {
	                digitNum = 0;
	                goto NEXT;
	            }
	
	            if (0 == digitNum) {
	                result.err = CALCULATE_ERR_REPEAT;
	                goto END; 
	            }
	
	            if (CALCULATE_MAX_DIGITS == digitsNum - 1) {
	                result.err = -4;
	                goto END;
	            }
	
	            digits[digitsNum++] = atof(digit);
	            memset(digit, '\0', sizeof(digit));
	            digitNum = 0;
	    
            NEXT:
                operator[optNum++] = *pointer;
            }
        
            break;

        case '(':
        {
            char *pointer_son;

            int ExistEnd = 0;

            pointer_son = ++pointer;

            while(length--) {
                if ('(' == *pointer) {
                    ExistEnd--;
                }
                if (')' == *pointer) {
                    ExistEnd++;
                }
                if (1 == ExistEnd) {
                    break;
                }
                pointer++;
            }

            /* 括号内的字符串执行递归 */

            CALCULATERESULT result_son = Utils_Calculate(pointer_son, pointer - pointer_son);
            if (0 > result_son.err) {
                result.err = result_son.err;
                goto END;
            }

            digits[digitsNum++] = result_son.value;

            memset(digit, '\0', sizeof(digit));
            digitNum = -1;
        }

            break;

        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        case '.':

            digit[digitNum++] = *pointer;
            break;
        
        case ' ':
        case '\n':

            break;

        default:

            result.err = CALCULATE_ERR_SYMBOL;
            goto END; 
        }

        if (0 == length && 0 < digitNum) {
            digits[digitsNum++] = atof(digit);
            memset(digit, '\0', sizeof(digit));
            digitNum = 0;
        }

        pointer ++;
    }

    if (digitsNum != optNum + 1) {
        result.err = CALCULATE_ERR_NUMBER;
        goto END;
    }

    /* 消除"乘除"运算符 */

    for (idx = 0; idx < optNum; idx ++) {
        if ('*' == operator[idx]) {
            digits[idx+1] = digits[idx] * digits[idx+1];
            digits[idx] = 0;
            operator[idx] = '?';
        }
        if ('/' == operator[idx]) {
            digits[idx+1] = digits[idx] / digits[idx+1];
            digits[idx] = 0;
            operator[idx] = '?';
        }
    }


    for (idx = 0; idx < optNum; idx ++) {
        if ('?' == operator[idx]) {
            if (0 == idx) {
                operator[idx] = '+';
            } else {
                operator[idx] = operator[idx-1];
            }
        }
    }

    /* 顺序执行"加减"运算 */

    result.value = digits[0];

    for (idx = 0; idx < optNum; idx ++) {
        if ('+' == operator[idx]) {
            result.value += digits[idx + 1];
        }
        if ('-' == operator[idx]) {
            result.value -= digits[idx + 1];
        } 
    }

END:
    return result;
}

int main(int argc, char* argv[])
{
    char formula[1024];

    if (3 != argc) {
        printf("请输入正确的参数\n");
        return 0;
    }

    sprintf(formula, "%s", argv[2]);

    Utils_Strrpc(formula, "x", argv[1]);

    CALCULATERESULT resault = Utils_Calculate(formula, strlen(formula));

    printf("%g\n", resault.value);

    return 0;
}

测试

程序第一个参数为数值,第二个参数为公式,执行测试:

root@zth:~/newDigate# gcc test.c -o test
root@zth:~/newDigate# ./test 32.6 \(\(x-10.3\)*1.43+13.77\)*10.132
462.617
root@zth:~/newDigate# 
  • 14
    点赞
  • 92
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个简单的计算器程序,可以支持四则运算小数括号: ```c #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define MAX_EXPR_LEN 100 // 表达式最大长度 // 运算符栈 char opstack[MAX_EXPR_LEN]; int op_top = -1; // 数字栈 double numstack[MAX_EXPR_LEN]; int num_top = -1; // 运算符优先级 int priority(char op) { switch (op) { case '+': case '-': return 1; case '*': case '/': return 2; case '(': return 0; } return -1; } // 计算表达式 double evaluate(char *expr) { op_top = -1; num_top = -1; char *p = expr; while (*p != '\0') { if (isdigit(*p) || *p == '.') { // 数字入栈 double num = strtod(p, &p); numstack[++num_top] = num; } else if (*p == '(') { // 左括号入栈 opstack[++op_top] = '('; p++; } else if (*p == ')') { // 右括号计算 while (op_top >= 0 && opstack[op_top] != '(') { char op = opstack[op_top--]; double b = numstack[num_top--]; double a = numstack[num_top--]; switch (op) { case '+': numstack[++num_top] = a + b; break; case '-': numstack[++num_top] = a - b; break; case '*': numstack[++num_top] = a * b; break; case '/': numstack[++num_top] = a / b; break; } } if (op_top >= 0 && opstack[op_top] == '(') { op_top--; } p++; } else { // 运算符计算 while (op_top >= 0 && priority(opstack[op_top]) >= priority(*p)) { char op = opstack[op_top--]; double b = numstack[num_top--]; double a = numstack[num_top--]; switch (op) { case '+': numstack[++num_top] = a + b; break; case '-': numstack[++num_top] = a - b; break; case '*': numstack[++num_top] = a * b; break; case '/': numstack[++num_top] = a / b; break; } } opstack[++op_top] = *p++; } } while (op_top >= 0) { char op = opstack[op_top--]; double b = numstack[num_top--]; double a = numstack[num_top--]; switch (op) { case '+': numstack[++num_top] = a + b; break; case '-': numstack[++num_top] = a - b; break; case '*': numstack[++num_top] = a * b; break; case '/': numstack[++num_top] = a / b; break; } } return numstack[num_top]; } int main() { char expr[MAX_EXPR_LEN]; printf("请输入表达式:"); scanf("%s", expr); double result = evaluate(expr); printf("%s = %f\n", expr, result); return 0; } ``` 运行示例: ``` 请输入表达式:(1.2+2.3)*3.4-4.5/5.6 (1.2+2.3)*3.4-4.5/5.6 = 8.139286 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值