目录

  • 前言
  • 目标功能
  • 不带括号的公式处理
  • 带括号的公式处理
  • 源码
  • 测试

前言

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


提示:以下为正文内容

目标功能

假设有如下参数:

 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#

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

  1. c语言利用栈实现四则运算(包括括号小数),DataStructure_1用栈实现四则运算(c语言)...

    有一句计算机界中的至理名言: 程序=数据结构+算法 可见数据结构是多么地重要啊......呵呵 今天开始复习了一下数据结构 , 解决了以前的一个问题: 用栈这个数据结构实现四则运算 算法思想是借鉴了& ...

  2. jQueryEasyUI实现房贷计算器详细教程1--HTML部分

    1.HTML文件的基本构成 我们从最基础的一段HTML代码开始编程: <!DOCTYPE html> <html><head><meta charset=&q ...

  3. C#实现多语言切换详细教程(附源码)

    源代码下载地址: CSDN:点击下载 GitHub:点击下载 环境说明:Windows10,VS2017,.NET Framework4.0 详细步骤: 1.新建一个C#的.NET Framework ...

  4. jQueryEasyUI实现房贷计算器详细教程2--jQuery部分

    1.从载入JavaScript开始 jQuery 是一个 JavaScript 库,极大地简化了 JavaScript 编程.这一部分介绍下载和载入jQuery. 源代码: <script sr ...

  5. VS code配置C语言,详细教程,初学者专用(附需要的插件)(win系统)

    vscode配置C语言首先下载vscode,这里我就不多说了. 我们自己在使用vscode配置c语言后发现c语言根本就不能运行,是因为我们缺少一个配置c语言的插件需要我们自己下载,因为vscode不提 ...

  6. 我的Go+语言初体验——基于CentOS系统搭建Go+语言环境详细教程

    文章目录

  7. 新手C语言开发详细教程

    1. 下载资源包(编写软件是NotePad++, 编译工具是gcc) 代码编写软件网址:https://download.csdn.net/download/m0_52983689/87128595 ...

  8. oracle数据库sql培训,Oracle数据库SQL语言实战培训教程(全面、详细、案例、精讲)套餐...

    风哥oracle数据库SQL语言实战培训教程(案例.精讲)套餐,DBA必备技能. 套餐介绍: 风哥Oracle数据库SQL语言实战培训教程(案例.精讲)套餐,DBA必备技能. 内容: SQL语言基础入 ...

  9. Python语言学习之数值、小数、空格那些事:python和数值、小数、空格的使用方法之详细攻略

    Python语言学习之数值.小数.空格那些事:python和数值.小数.空格的使用方法之详细攻略 目录 Python与数值那些事 1.python保留两位小数/保留小数点位数 Python去掉空格的方 ...

  10. c4d语言包英文,Maxon Cinema 4D R23(C4D R23)中英文安装及设置详细教程(附下载)

    中文包安装方法: 离线方法:打开下载好的语言包文件,在顶部菜单栏找到"Help>Manual Installation" 打开语言包的位置,选择要安装的.c4dupdate包 ...

最新文章

  1. Dubbo基础专题——第二章(Dubbo工程简单实践)
  2. 【剑指offer-Java版】30最小的K个数
  3. 立足优势,你的网站会更精彩
  4. java 银行存取款_用Java编写银行存钱取钱
  5. ffmpeg合并音频(转)
  6. 创建一个简单的ArcGIS Server ASP.NET网页
  7. COGS2421 简单的Treap
  8. On the Robustness of Semantic Segmentation Models to Adversarial Attacks论文解读
  9. Mac 苹果电脑创建一个新的管理员账号
  10. 电脑进入pe时蓝屏_进PE蓝屏的几个原因
  11. Liber 1. 《活着》:人生如逆旅,我亦是行人
  12. OpenGL:太阳、地球、月球模型模拟动画
  13. vue导出excel加一个进度条_Vue实现在前端导出Excel
  14. c语言放空一个数组,数组越界真可怕,莫名就闯到了别人家
  15. 制图操作案例:ArcGIS Pro鹰眼图快速制图
  16. python 条形图 负值_使用python matplotlib获取正负值的堆积条形图
  17. rdkit 分子性质描述符(Descriptors)
  18. 网关 Spring Cloud Gateway 监控 actuator
  19. select2.js实现拼音搜索支持
  20. 小程序合成海报图片,高度自适应

热门文章

  1. VMware Fusion 启动物理磁盘及U盘的方法
  2. java 获取保存存储路径配置文件
  3. ThinkPHP学生管理系统
  4. 福建省c语言上机题库,二级c语言上机题库
  5. nokia 5220 XpressMusic 自己刷机
  6. 最佳 Web 编程语言都有哪些?
  7. 入选《PHP领域内容榜》,感谢CSDN,感谢各位浏览过我的朋友
  8. 国家java认证考试报名入口,值得一读!
  9. 试图加载 Crystal Reports 运行时出现错误
  10. HFSS19 官方中文教程系列 L04