热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

具备括号和分数功能的高级四则运算计算器

本研究基于C语言开发了一款支持括号和分数运算的高级四则运算计算器。该计算器通过模拟手算过程,对每个运算符进行优先级标记,并按优先级从高到低依次执行计算。其中,加减运算的优先级最低,为0。此外,该计算器还支持复杂的分数运算,能够处理包含括号的表达式,提高了计算的准确性和灵活性。

用C语言实现的带括号四则运算计算器,原理简单,即模拟笔算,将每个运算符标记等级,计算时按照等级由高到低进行计算。加减运算为0级,乘除运算为1级,每进入一层括号等级加2。使用两个链表分别储存运算符与数字。主程序调用之前实现的两个模块,一个是链表,另一个是分数计算。链表代码在下一篇文章,只贴出主程序和分数计算部分。

主程序,检查算式是否合法的函数未实现

1 #include "list.h"
2 #include "sz.h"
3
4 /*内部类型、常量、函数*/
5
6 #define LEVEL_NUM 20 //支持的运算级数
7
8 typedef struct
9 {
10 List *oper; //存运算符的链表,data段类型为Op *
11 List *num; //存数字的链表,data段类型为Fract *
12 int oper_num[LEVEL_NUM]; //存每一级的运算符个数
13 }Pack;
14
15 typedef struct
16 {
17 char oper;
18 int level;
19 }Op; //运算符及对应的级别,加减0级,乘除1级,每进入一层括号运算符对应的级别加2
20
21
22 static void Convert(char equation[],Pack *pack);
23 static int str2int(char str[],int start,int end);
24 static int GetSE(char str[],int s,int flag);
25 static void Compute(Pack *pack,Fract *ans);
26
27
28 int main(void)
29 {
30 char equation[100];
31 Fract ans;
32 while(1)
33 {
34 scanf("%s",equation);
35 calc(equation,&ans);
36 printf("%d/%d\n",ans.numer,ans.deno);
37 }
38 return 0;
39 }
40
41 void calc(char equation[],Fract *ans)
42 {
43 Pack pack;
44
45 //检查及完善equation,该函数未实现!!
46
47 //转换并存入链表
48 Convert(equation,&pack);
49
50 //使用链表计算,并释放
51 Compute(&pack,ans);
52
53 }
54
55 //特别说明
56 //对于"(-数字"这种形式,会导致str2int的参数start>end,正好会转化成"(0-数字"的形式
57 //因此没有用库函数
58 void Convert(char equation[],Pack *pack)
59 {
60 int i,base,start;
61
62 Op *op;
63 Fract *num;
64
65 //初始化
66 pack->num=CreateList();
67 pack->oper=CreateList();
68 for(i=0;i)
69 pack->oper_num[i]=0;
70
71 start=GetSE(equation,0,1);
72 base=0; //存级别的基,每进入一层括号基加2
73 for(i=0;equation[i];i++)
74 switch(equation[i])
75 {
76 case '+':case '-':case '*':case '/':
77 //添加运算符
78 op=(Op *)malloc(sizeof(Op));
79 op->oper=equation[i];
80 op->level=base+
81 ( (equation[i]=='+'||equation[i]=='-')?0:1);
82 AddNode(pack->oper,op,pack->oper->n); //插入到链表尾
83 pack->oper_num[op->level]++;
84
85 //添加数字
86 num=(Fract *)malloc(sizeof(Fract));
87 num->numer=str2int(equation,start,GetSE(equation,i-1,-1));
88 num->deno=1;
89 AddNode(pack->num,num,pack->num->n);
90 start=GetSE(equation,i+1,1); //为下一个数字准备
91 break;
92 case '(':
93 base+=2;
94 break;
95 case ')':
96 base-=2;
97 break;
98 default: //数字字符
99 break;
100 }
101
102 //运算符和数字成对出现,存入最后多出的数字
103 num=(Fract *)malloc(sizeof(Fract));
104 num->numer=str2int(equation,start,GetSE(equation,i-1,-1));
105 num->deno=1;
106 AddNode(pack->num,num,pack->num->n);
107 }
108
109
110 //将由start和end脚标确定的字符串转换为整数
111 int str2int(char str[],int start,int end)
112 {
113 int i,s=0;
114 for(i&#61;start;i<&#61;end;i&#43;&#43;)
115 s&#61;s*10&#43;str[i]-&#39;0&#39;;
116 return s;
117 }
118
119
120 //从s开始向前或向后找第一个数字字符的角标
121 //flag为1向后&#xff0c;-1向前
122 int GetSE(char str[],int s,int flag)
123 {
124 int i;
125 for(i&#61;s;i>&#61;0 && str[i] && !isdigit(str[i]);i&#43;&#61;flag)
126 ;
127 return i;
128 }
129
130 void Compute(Pack *pack,Fract *ans)
131 {
132 //前一运算符&#xff0c;运算符
133 //第一个数字,第二个数字
134 Node *pop,*op,*num,*nnum;
135 int i;
136
137 //找到最高不为0的一级
138 for(i&#61;LEVEL_NUM-1;i>&#61;0 && !pack->oper_num[i];i--)
139 ;
140
141 for(;i>&#61;0;i--) //由高到低级依次计算
142 for(pop&#61;pack->oper->head,op&#61;pack->oper->head->next,num&#61;pack->num->head->next;
143 pack->oper_num[i] ; )
144 if( ((Op*)(op->data))->level&#61;&#61;i ) //找到级别为i的运算符
145 {
146 pack->oper_num[i]--;
147 switch( ((Op*)(op->data))->oper)
148 {
149 //计算&#xff0c;结果存入第一个数中
150 case &#39;&#43;&#39;:Plus(num->data,num->next->data);
151 break;
152 case &#39;-&#39;:Minus(num->data,num->next->data);
153 break;
154 case &#39;*&#39;:Multiply(num->data,num->next->data);
155 break;
156 case &#39;/&#39;:Divide(num->data,num->next->data);
157 break;
158 default:
159 printf("\nCompute函数出现不可能运算符 %c\n",((Op*)(op->data))->oper);
160 exit(0);
161 break;
162 }
163
164 //删除计算完成的运算符、数字
165 pack->num->n--;
166 pack->oper->n--;
167 pop->next&#61;op->next;
168 nnum&#61;num->next;
169 num->next&#61;nnum->next;
170 free(nnum->data);free(op->data);
171 free(nnum);free(op);
172
173 op&#61;pop->next; //恢复op的指向
174 }
175 else //没找到时继续遍历链表
176 pop&#61;op,op&#61;op->next,num&#61;num->next;
177
178 //计算完成后&#xff0c;仅剩一个的数字为结果&#xff0c;运算符链表没内容&#xff0c;储存运算符级别的个数的数组各元素为0
179 if(pack->num->n!&#61;1 || pack->oper->n || pack->oper_num[0])
180 {
181 printf("Compute函数内变量异常&#xff0c;数字个数 %d&#xff0c;运算符个数 %d&#xff0c;0级个数 %d",
182 pack->num->n,pack->oper->n,pack->oper_num[0]);
183 exit(0);
184 }
185 (*ans)&#61;*(Fract *)pack->num->head->next->data;
186 DestroyList(pack->num);
187 DestroyList(pack->oper);
188 }

sz.c

1 #ifndef SZ_H
2 #define SZ_H
3
4 //只有calc函数对外&#xff0c;可以去掉主函数来当做一个计算模块使用
5 //只要在项目中添加sz、list、fract
6
7 #include
8 #include "fract.h"
9
10 void calc(char equation[],Fract *ans);
11
12 #endif

sz.h

分数计算部分

1 #include "fract.h"
2
3 static int commom_divisor(int a,int b); //最大公约数
4 static int common_multiple(int a,int b);//最小公倍数
5 static void reduce(int *num1,int *num2); //约分
6
7
8 void Plus(Fract *num1,Fract *num2)
9 {
10 int deno;//公分母
11
12 if(num1->numer&#61;&#61;0) //排除0值计算
13 {
14 *num1&#61;*num2;
15 return;
16 }
17 else if(num2->numer&#61;&#61;0) return;
18
19 deno&#61;common_multiple(num1->deno,num2->deno);
20 num1->numer&#61;deno/num1->deno*num1->numer&#43;deno/num2->deno*num2->numer;
21 num1->deno&#61;deno;
22
23 }
24
25 void Minus(Fract *num1,Fract *num2)
26 {
27 num2->numer&#61;-num2->numer;
28 Plus(num1,num2);
29 }
30
31 void Multiply(Fract *num1,Fract *num2)
32 {
33 if(num1->numer&#61;&#61;0)return;
34 else if(num2->numer&#61;&#61;0)
35 {
36 num1->numer&#61;0;
37 return;
38 }
39
40 reduce(&num1->deno,&num2->numer);
41 reduce(&num1->numer,&num2->deno);
42
43 num1->numer*&#61;num2->numer;
44 num1->deno*&#61;num2->deno;
45
46 }
47
48 void Divide(Fract *num1,Fract *num2)
49 {
50 int temp;
51 if(num2->numer&#61;&#61;0)
52 {
53 printf("除数不能为0\n");
54 exit(0);
55 }
56 temp&#61;num2->numer;
57 num2->numer&#61;num2->deno;
58 num2->deno&#61;temp;
59 Multiply(num1,num2);
60 }
61
62
63 static void reduce(int *num1,int *num2) //约分并保持原来的正负号
64 {
65 int temp,i;
66
67 /*i为0表示都为正&#xff0c;i为1表示num1为正&#xff0c;2表示num2为正&#xff0c;3表示都为负*/
68 if(*num1<0)
69 {
70 *num1&#61;-*num1;
71 if(*num2<0)
72 {
73 *num2&#61;-*num2;
74 i&#61;3;
75 }
76 else i&#61;2;
77 }
78 else
79 if(*num2<0)
80 {
81 *num2&#61;-*num2;
82 i&#61;1;
83 }
84 else i&#61;0;
85
86 temp&#61;commom_divisor(*num1,*num2);
87 *num1/&#61;temp;
88 *num2/&#61;temp;
89
90 switch(i)
91 {
92 case 0:break;
93 case 1:*num2&#61;-*num2;break;
94 case 2:*num1&#61;-*num1;break;
95 case 3:*num1&#61;-*num1;*num2&#61;-*num2;break;
96 }
97 }
98
99
100 static int commom_divisor(int a,int b)
101 {
102 int temp,r;
103
104 if(a<b)
105 {
106 temp&#61;a;
107 a&#61;b;
108 b&#61;temp;
109 }
110
111 while((r&#61;a%b))
112 {
113 a&#61;b;
114 b&#61;r;
115 }
116
117 return b;
118 }
119
120 static int common_multiple(int a,int b)
121 {
122 return a*b/commom_divisor(a,b);
123 }

fract.c

1 #ifndef FRACT_H
2 #define FRACT_H
3
4 #include
5 #include
6
7 //如果有负号则在分子上
8 typedef struct
9 {
10 int numer; //分子
11 int deno; //分母
12 }Fract;
13
14 //分数的四则运算&#xff0c;结果存在num1中
15 void Plus(Fract *num1,Fract *num2);
16 void Minus(Fract *num1,Fract *num2);
17 void Multiply(Fract *num1,Fract *num2);
18 void Divide(Fract *num1,Fract *num2);
19
20 #endif

fract.h

 

控制台程序源代码 sz.7z

 

借用如鹏的对话框模版&#xff0c;及上面的计算器部分&#xff0c;实现的图形计算器

代码及程序 calc.7z

 

转:https://www.cnblogs.com/zackcoder/p/3246384.html



推荐阅读
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • 在Kohana 3框架中,实现最优的即时消息显示方法是许多开发者关注的问题。本文将探讨如何高效、优雅地展示flash消息,包括最佳实践和技术细节,以提升用户体验和代码可维护性。 ... [详细]
  • 第六章:枚举类型与switch结构的应用分析
    第六章深入探讨了枚举类型与 `switch` 结构在编程中的应用。枚举类型(`enum`)是一种将一组相关常量组织在一起的数据类型,广泛存在于多种编程语言中。例如,在 Cocoa 框架中,处理文本对齐时常用 `NSTextAlignment` 枚举来表示不同的对齐方式。通过结合 `switch` 结构,可以更清晰、高效地实现基于枚举值的逻辑分支,提高代码的可读性和维护性。 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • 2012年9月12日优酷土豆校园招聘笔试题目解析与备考指南
    2012年9月12日,优酷土豆校园招聘笔试题目解析与备考指南。在选择题部分,有一道题目涉及中国人的血型分布情况,具体为A型30%、B型20%、O型40%、AB型10%。若需确保在随机选取的样本中,至少有一人为B型血的概率不低于90%,则需要选取的最少人数是多少?该问题不仅考察了概率统计的基本知识,还要求考生具备一定的逻辑推理能力。 ... [详细]
  • 本文介绍了UUID(通用唯一标识符)的概念及其在JavaScript中生成Java兼容UUID的代码实现与优化技巧。UUID是一个128位的唯一标识符,广泛应用于分布式系统中以确保唯一性。文章详细探讨了如何利用JavaScript生成符合Java标准的UUID,并提供了多种优化方法,以提高生成效率和兼容性。 ... [详细]
  • Android中将独立SO库封装进JAR包并实现SO库的加载与调用
    在Android开发中,将独立的SO库封装进JAR包并实现其加载与调用是一个常见的需求。本文详细介绍了如何将SO库嵌入到JAR包中,并确保在外部应用调用该JAR包时能够正确加载和使用这些SO库。通过这种方式,开发者可以更方便地管理和分发包含原生代码的库文件,提高开发效率和代码复用性。文章还探讨了常见的问题及其解决方案,帮助开发者避免在实际应用中遇到的坑。 ... [详细]
  • 在使用SSH框架进行项目开发时,经常会遇到一些常见的问题。例如,在Spring配置文件中配置AOP事务声明后,进行单元测试时可能会出现“No Hibernate Session bound to thread”的错误。本文将详细探讨这一问题的原因,并提供有效的解决方案,帮助开发者顺利解决此类问题。 ... [详细]
  • 手指触控|Android电容屏幕驱动调试指南
    手指触控|Android电容屏幕驱动调试指南 ... [详细]
  • 本文探讨了 Java 中 Pair 类的历史与现状。虽然 Java 标准库中没有内置的 Pair 类,但社区和第三方库提供了多种实现方式,如 Apache Commons 的 Pair 类和 JavaFX 的 javafx.util.Pair 类。这些实现为需要处理成对数据的开发者提供了便利。此外,文章还讨论了为何标准库未包含 Pair 类的原因,以及在现代 Java 开发中使用 Pair 类的最佳实践。 ... [详细]
  • AIX编程挑战赛:AIX正方形问题的算法解析与Java代码实现
    在昨晚的阅读中,我注意到了CSDN博主西部阿呆-小草屋发表的一篇文章《AIX程序设计大赛——AIX正方形问题》。该文详细阐述了AIX正方形问题的背景,并提供了一种基于Java语言的解决方案。本文将深入解析这一算法的核心思想,并展示具体的Java代码实现,旨在为参赛者和编程爱好者提供有价值的参考。 ... [详细]
  • 深入理解 Java 控制结构的全面指南 ... [详细]
  • JavaScript XML操作实用工具类:XmlUtilsJS技巧与应用 ... [详细]
  • 蓝桥杯物联网基础教程:通过GPIO输入控制LED5的点亮与熄灭
    本教程详细介绍了如何利用STM32的GPIO接口通过输入信号控制LED5的点亮与熄灭。内容涵盖GPIO的基本配置、按键检测及LED驱动方法,适合具有STM32基础的读者学习和实践。 ... [详细]
  • 本文详细探讨了MySQL数据库实例化参数的优化方法及其在实例查询中的应用。通过具体的源代码示例,介绍了如何高效地配置和查询MySQL实例,为开发者提供了有价值的参考和实践指导。 ... [详细]
author-avatar
ll66068ll你
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有