数据结构课程设计简单计算器C语言.docx
《数据结构课程设计简单计算器C语言.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计简单计算器C语言.docx(32页珍藏版)》请在冰点文库上搜索。
![数据结构课程设计简单计算器C语言.docx](https://file1.bingdoc.com/fileroot1/2023-7/19/ecab241e-d78b-4d5d-9fd2-715ae3c9031e/ecab241e-d78b-4d5d-9fd2-715ae3c9031e1.gif)
数据结构课程设计简单计算器C语言
郑州师范学院
信息科学与技术学院
《简单计算器》课程设计报告
设计题目:
简单计算器
班级:
B15计科二班
组长:
组员:
指导教师:
完成日期:
2016年12月23日
成绩:
摘要
本次选做的课程设计是实现简单计算器的问题。
计算器是一个常用的运算工具,本次课题要求用程序语言的方式解决问题。
此问题仅使用数据结构中的栈操作就可以解决此问题。
而在为了方便使用,添加了easyx图形库实现了UI设计。
为了接近平常使用的计算器,特地创建死循环而且添加了“CE”清空输入和“<-”删除键来控制输入错误或者循环使用的问题。
在UI方面主要是实现按键和点击响应等交互,方便输入和修改,在程序框上面有输入和显示结果的文本框。
在计算过程中,以栈出栈进站的特性把中缀形式的算数表达式转化为计算机方便计算的后缀表达式,最后计算出结果以文本方式显示在结果输出框内。
1需求分析
1.1功能简介及分析
本次选做的课程设计是实现简单的计算器并且添加UI的交互。
此计算器是以软件的形式实现的计算器,运行在windows系统。
计算器在功能上分为三类,分别是:
常见计算器,专用计算器,综合功能计算器。
常见的计算器又分为四种:
1简单型计算器:
只实现基本的加减乘除和括号运算。
②科学型计算器:
可以进行乘方、开方、指数、对数、三角函数、统计等方面的运算,又称函数计算器。
③程序员计算器:
专门为程序员设计的计算器,主要特点是支持And,Or,Not,Xor:
最基本的与或非和异或操作,移位操作Lsh,Rsh:
全称是LeftShift和RightShift,也就是左移和右移操作,你需要输入你要移动的位数(不能大于最大位数)RoL,RoR:
全称是RotateLeft和RotateRight,对于RoL来讲,就是向左移动一位,并将移出的那位补到最右边那位上,RoR类似。
④统计型计算器:
为有统计要求的人员设计的设计的计算器。
本次课程设计只是实现了常见的简单计算器:
在界面上:
简单的计算器需要有简单的按键和按键响应,有输入和结果的显示。
在功能上:
能进行加减乘除混合运算,可以使用括号,有“M”键可以存储结果,以便下次计算使用,可以对输入的文本删除和重置。
并且可以在重置后继续使用。
1.2设计平台
Windows7操作系统;VisualStudio2015
2概要设计
2.1Trans函数
主要功能中缀算术表达式转化成后缀表达式,然后存到栈里,以便计算时使用,转化时包括对小括号的匹配。
2.2Compvalue函数
主要功能是对栈中的后缀表达式进行计算,然后返回float类型的结果。
2.3GetKey函数
GetKey主要是在UI界面中获取按键然后保存成字符数组或者对字符数组的增减操作的函数。
此函数为内置死循环,可以重复使用。
3详细设计和实现
实现软件形式的常用简单计算机,主要用到栈的特点,把平常使用的表达式,转化为能够让计算机计算的逆波兰表达式。
中缀表达式(或中缀记法)是一个通用的算术或逻辑公式表示方法,操作符是以中缀形式处于操作数的中间(例:
3+4),中缀表达式是人们常用的算术表示方法。
与前缀表达式(例:
+34)或后缀表达式(例:
34+)相比,中缀表达式不容易被计算机解析,但仍被许多程序语言使用,因为它符合人们的普遍用法。
与前缀或后缀记法不同的是,中缀记法中括号是必需的。
计算过程中必须用括号将操作符和对应的操作数括起来,用于指示运算的次序。
例:
(1)8+4-6*2用后缀表达式表示为:
62*84+-
(2)2*(3+5)-4+7/1用后缀表达式表示为:
35+2*71/4-+
3.1转化为逆波兰式
首先需要分配2个栈,一个作为临时存储运算符的栈S1(含一个结束符号),一个作为输入逆波兰式的栈S2(空栈),S1栈可先放入优先级最低的运算符#,注意,中缀式应以此最低优先级的运算符结束。
可指定其他字符,不一定非#不可。
从中缀式的左端开始取字符,逐序进行如下步骤:
(1)若取出的字符是操作数,则分析出完整的运算数,该操作数直接送入S2栈
(2)若取出的字符是运算符,则将该运算符与S1栈栈顶元素比较,如果该运算符优先级大于S1栈栈顶运算符优先级,则将该运算符进S1栈,否则,将S1栈的栈顶运算符弹出,送入S2栈中,直至S1栈栈顶运算符低于(不包括等于)该运算符优先级,则将该运算符送入S1栈。
(3)若取出的字符是“(”,则直接送入S1栈底。
(4)若取出的字符是“)”,则将距离S1栈栈底最近的“(”之间的运算符,逐个出栈,依次送入S2栈,此时抛弃“(”。
(5)重复上面的1~4步,直至处理完所有的输入字符。
(6)若取出的字符是“#”,则将S1栈内所有运算符(不包括“#”),逐个出栈,依次送入S2栈。
完成以上步骤,S2栈便为逆波兰式输出结果。
不过S2应做一下逆序处理。
便可以按照逆波兰式的计算方法计算了!
例如转换:
2-(1+2)*3+4
转换后的逆波兰表达式是:
212+3*-4+
3.2计算逆波兰式
逆波兰式的计算同样用到了栈的特点,首先需要建立一个空栈T,然后从头遍历逆波兰式,如果是数字则直接放到栈顶,如果遇到操作符则连续取出两个栈顶数据,分别赋值给n1,n2,再根据操作符计算n1和n2,把得到的结果放到T栈栈顶,继续操作,直到遍历完毕。
以上面的例子计算过程如图:
最后得出的结果是-3,即2-(1+2)*3+4=-3;
所以计算的具体过程是先转化中缀表达式为逆波兰表达式,然后由逆波兰表达式计算出结果,在转化的过程和最后的计算过程都用到了栈的思想,利用栈的进栈和出栈的特点实现转换。
3.3实现流程图
简单运行流程图
3.3部分具体程序
//界面显示文字,”$”表示结束位置
charKeyStr[][4]={{"CE"},{"<-"},{"M"},{"/"}
{"("},{")"},{"^"},{"^"}
{"7"},{"8"},{"9"},{"*"}
{"4"},{"5"},{"6"},{"+"}
{"1"},{"2"},{"3"},{"-"}
{"00"},{"0"},{"."},{"="},{"$"}};
voidTrans(STR*InStr,charLasts[])
{/*将算术表达式转化为后缀表达式*/
inti=1;
charStack[MAX];/*作为栈使用*/
charChStr=InStr->Str[i];//用于保存数组里的临时元素
i++;
intLastStrPos=1,StackTop=0;//StackTop用于表示栈顶
while(ChStr!
='#'){
switch(ChStr){
case'(':
/*判定为左括号*/
StackTop++;
Stack[StackTop]=ChStr;
break;
case')':
/*判定为右括号*/
while(Stack[StackTop]!
='('){
Lasts[LastStrPos]=Stack[StackTop];
StackTop--;
LastStrPos++;
}
StackTop--;//扔掉(
break;
case'+':
/*判定为加减号*/
case'-':
while(StackTop!
=0&&Stack[StackTop]!
='('){
Lasts[LastStrPos]=Stack[StackTop];
StackTop--;
LastStrPos++;
}
StackTop++;//保留(
Stack[StackTop]=ChStr;
break;
case'*':
/*判定为乘除号*/
case'/':
while(Stack[StackTop]=='*'||Stack[StackTop]=='/'){
Lasts[LastStrPos]=Stack[StackTop];//如果栈顶是*或者/弹出,放到后缀数组里
StackTop--;
LastStrPos++;
}
StackTop++;
Stack[StackTop]=ChStr;
break;
case'':
break;//忽略空格
default:
while(ChStr>='0'&&ChStr<='9'||ChStr=='.'){/*判定为数字*/
Lasts[LastStrPos]=ChStr;
LastStrPos++;
ChStr=InStr->Str[i];
i++;
}
i--;
Lasts[LastStrPos]='';//输出的时候隔开元素
LastStrPos++;
}
ChStr=InStr->Str[i];i++;
}
while(StackTop!
=0){
Lasts[LastStrPos]=Stack[StackTop];
LastStrPos++;
StackTop--;
}
Lasts[LastStrPos]='';
LastStrPosT=LastStrPos;
}
floatCompvalue(charLastStrTemp[]){/*计算后缀表达式的值*/
floatStack[MAX];/*作为栈使用*/
charChStr;//临时栈元素
intStackTop=0;/*LastStrPos为Lasts下标,StackTop为Stack下标*/
intLastStrPos=1;
ChStr=LastStrTemp[LastStrPos];
LastStrPos++;
while(ChStr!
=''){
switch(ChStr){
case'+':
Stack[StackTop-1]=Stack[StackTop-1]+Stack[StackTop];
StackTop--;
break;
case'-':
Stack[StackTop-1]=Stack[StackTop-1]-Stack[StackTop];
StackTop--;
break;
case'*':
Stack[StackTop-1]=Stack[StackTop-1]*Stack[StackTop];
StackTop--;
break;
case'/':
if(Stack[StackTop]!
=0)
Stack[StackTop-1]=Stack[StackTop-1]/Stack[StackTop];
else{
exit(0);/*异常退出*/
}
StackTop--;
break;
default:
floatNumStr=0;//把数字字符转化为数字
boolFlNum=0;
while(ChStr>='0'&&ChStr<='9'||ChStr=='.'){
if(ChStr=='.'){
FlNum=1;
}
elseif(!
FlNum){
NumStr=10*NumStr+ChStr-'0';/*将数字字符转化为对应的数值*/
}
elseif(FlNum){
NumStr+=0.1*(ChStr-'0');/*计算小数*/
}
ChStr=LastStrTemp[LastStrPos];
LastStrPos++;
}
StackTop++;
Stack[StackTop]=NumStr;
}
ChStr=LastStrTemp[LastStrPos];
LastStrPos++;
}
returnStack[StackTop];
}
voidGetKey(){
/*FlushMouseMsgBuffer清空鼠标消息缓冲区。
GetMouseMsg获取一个鼠标消息。
如果当前鼠标消息队列中没有,就一直等待。
MouseHit检测当前是否有鼠标消息。
MOUSEMSG保存鼠标消息的结构体。
*/
MOUSEMSGMsg;
RECTr={0,WINKEYY*2/3,WINSIZEX,WINKEYY*2};
IMAGEClearImgUp,ClearImgDown;
intProPos=0;//上一个点击的按钮
inttemp=0;//当前点击的按钮
intInCon=0;//输入的字符数
intTempI=0;
floatLastStrTemp=LastV;
charStrTemp[MAX];
charM_Str[20]={'/0'};
FlushMouseMsgBuffer();
getimage(&ClearImgUp,1,1,WINSIZEX,WINKEYY*2/3);//获得输入区域的截图,用于覆盖原先输入的内容
getimage(&ClearImgDown,1,WINKEYY*2/3,WINSIZEX,WINKEYY*2);//获得输出区域的截图,用于覆盖原先输入的内容
while(TRUE){
Msg=GetMouseMsg();
if(Msg.uMsg){
temp=JudgePos(Msg.x,Msg.y);
switch(Msg.uMsg){
caseWM_LBUTTONDOWN:
setlinecolor(YELLOW);
rectangle(Pos[temp].x[0],Pos[temp].y[0],Pos[temp].x[1],Pos[temp].y[1]);
switch(temp){
case1:
GetStr[0]='\0';
putimage(1,1,&ClearImgUp);
putimage(1,WINKEYY*2/3,&ClearImgDown);
InCon=0;
PrintStr();
break;
case2:
if(InCon>0)//判断是否有输入的字符
GetStr[InCon-1]='\0';
putimage(1,1,&ClearImgUp);
InCon--;
PrintStr();
break;
case3:
strcat_s(GetStr,M_Str);
InCon++;
PrintStr();
break;
case24:
settextstyle(50,0,_T("PrestigeEliteStd"));//设置字体大小,宽度,文字样式
putimage(1,WINKEYY*2/3,&ClearImgDown);
GiveStr(GetStr,TheLastStr);
drawtext(_T(TheLastStr),&r,DT_RIGHT|DT_VCENTER|DT_SINGLELINE);
break;
case7:
case8:
break;
default:
strcat_s(GetStr,KeyStr[temp-1]);
InCon++;
PrintStr();
}
Sleep(50);
break;
caseWM_RBUTTONDOWN:
setlinecolor(BLUE);
rectangle(Pos[temp].x[0],Pos[temp].y[0],Pos[temp].x[1],Pos[temp].y[1]);
switch(temp){
case3:
strcpy(M_Str,TheLastStr);
break;
}
break;
}
}
setlinecolor(BLACK);
rectangle(Pos[ProPos].x[0],Pos[ProPos].y[0],Pos[ProPos].x[1],Pos[ProPos].y[1]);
if(temp!
=0){
setlinecolor(RED);
rectangle(Pos[temp].x[0],Pos[temp].y[0],Pos[temp].x[1],Pos[temp].y[1]);
ProPos=temp;
}
}
}
4调试与操作说明
4.1调试情况
这次的课程设计的代码很冗长,在实现整个思路之后难免会有很多错误。
编写代码过程中遇到很多错误和难题。
不过经过一点点的改正和攻克,错误也慢慢地变少,难题也逐个解开。
在计算机领域代码无论在逻辑上还是在编写上都不允许有一点错误,因为一点的错误就会使整个程序崩溃,有时即便能够成功运行,得出的结果也有可能和预期的结果千差万别,但是也是因为这样的严谨编写和工作学习中,使得调试或者编写代码的人逐渐培养出了有耐心,有毅力,并且严谨细心的心境。
一般在编写代码过程留下的逻辑错误或者编写错误都会在调试的时候遇到,这个时候就体现出了调试的重要性。
调试可以使程序的可运行性、健壮性、效率性上大幅度提高。
本程序在调试中遇到了很多问题,如计算结果的准确性、显示结果的准确性或者显示位置等等。
本程序还存在的问题是对计算的精确度支持低,只支持两位小数点,并且在应对错误计算或者错误输入没有进行匹配,这些问题都会在使用的过程中可能造成程序的崩溃,但是这些问题都会在以后的设计中进行完善和增强。
4.2操作说明
生成界面如图所示:
生成界面
当程序运行的时候会出现如上图所示,要求使用者通过按键输入运算表达式,使用者只需点击输入想要计算的表达式,最后点击“=”键后,系统便会计算出结果并且显示出来。
然后可以点击“<-”键删除修改表达式,或者通过“CE”键清空表达式和显示的结果,当然也可以通过点击“M”键暂时保存当前计算的结果,以便于下次计算使用(右键M把当前结果存到M中,默认是0,左键M输入当前M内的值)。
5设计总结
本次课程设计大概花费了两周的时间,其中10天左右用来编写和调试程序代码,4天左右用来对程序编写报告。
在此之间,遇到了许多编写上的难题和遇到错误的抓狂,但是这些都在耐心的,一次一次的调试中解决和攻克。
当再次总结后感觉收获很大,首先在编写代码上,增加自己的代码量,提高了编写的熟练度。
其次增加了对栈的使用和理解,也有了一些在使用栈的方法和经验。
然后是对界面设计的认识,如按键反馈、按键响应速度、颜色的搭配、字体的格式等等。
最后是对在修改和调试代码的经验,代码调试的过程是最辛苦的但也是最能体现编写代码能力的地方,看一个人代码编写能力怎么样,不是说让实现一个功能,而是在拿到一个存在诸多BUG时能一步步解决这些问题。
当然,在编写这个报告时,程序可能还是存在一些错误没被发现,这些都需要在后继的补充完善中慢慢发现和更正,还有是本程序功能少,只是实现了常用的简单计算器,对于和科学计算器或者程序员计算器等功能都为涉及,这些也将会成为我在后续的设计中一点点添加上去,因为我相信,每一个复杂的庞大的系统或者程序都是在简单的基础上一点点完善的。
也希望我能在后续的开发设计中能学习更多,收获更多,并且能一直坚持下去。
参考文献
[1]栾大成.大话数据结构[M].北京清华大学学研大厦A座:
清华大学出版社,2011.1-433
[2]甘勇,李晔,卢冰.C语言课程设计[M].北京市西城区右安门西街8号:
中国铁道出版社,2014.1-340
[3]严蔚敏,吴伟民.数据结构[M].北京清华大学学研大厦A座:
清华大学出版社,2007.1-334
[4]张宏林,孔艳,王哲等编著按实例学MicrosoftVisualStudio20056.0[M].北京:
人民邮电出版社,2000
[5]BrianWKernighan,DennisMRitchie.TheCProgrammingLanguage[M].Pubilished:
Prentice-Hall,2004.
[6]陈朔鹰,陈英.C语言趣味程序百例精解[M].北京理工大学:
北京理工大学出版社,1996.1-435
[7]谭浩强.C程序设计(第二版)[M].清华大学:
清华大学出版社,2014.1-350
[8]谭浩强.C语言程序设计题解与上机指导[M].清华大学:
清华大学出版社,2014.1-245
[9]白中英,戴志涛.计算机组成原理[M].北京东黄城根北街16号:
科学出版社,2013.1-350
全部代码如下:
VS2015调试通过(未加入错误检测)使用C11新标准
/***********************************
***数据结构期末课程设计***
************************************
***作业名称:
多项式计算器***
***使用的数据结构:
栈***
***UI:
使用easyx实现***
***********************************/
#include
#include
#include
#include
#include