热门标签 | 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



推荐阅读
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • Explore how Matterverse is redefining the metaverse experience, creating immersive and meaningful virtual environments that foster genuine connections and economic opportunities. ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 数据库内核开发入门 | 搭建研发环境的初步指南
    本课程将带你从零开始,逐步掌握数据库内核开发的基础知识和实践技能,重点介绍如何搭建OceanBase的开发环境。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
  • 本文介绍如何在 Android 中通过代码模拟用户的点击和滑动操作,包括参数说明、事件生成及处理逻辑。详细解析了视图(View)对象、坐标偏移量以及不同类型的滑动方式。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • 本文详细介绍如何使用Python进行配置文件的读写操作,涵盖常见的配置文件格式(如INI、JSON、TOML和YAML),并提供具体的代码示例。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 在金融和会计领域,准确无误地填写票据和结算凭证至关重要。这些文件不仅是支付结算和现金收付的重要依据,还直接关系到交易的安全性和准确性。本文介绍了一种使用C语言实现小写金额转换为大写金额的方法,确保数据的标准化和规范化。 ... [详细]
  • ImmutableX Poised to Pioneer Web3 Gaming Revolution
    ImmutableX is set to spearhead the evolution of Web3 gaming, with its innovative technologies and strategic partnerships driving significant advancements in the industry. ... [详细]
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社区 版权所有