C语言计算器设计实验报告
班级:11661 姓名: 学号:38号
一、实验目的:利用C语言编写一个简单的计算器,并能正确运行+,-,*,/四则运算。
二、实验内容:
1、 编写前分析;
(1)、根据实验目的,要求键盘录入表达式,并运行后输出结果;由于键盘录入的表达式含数字和运算符,所以要选择用字符串数据类型输入。
(2)、由于输入的是字符串,而只有数值类型的数据才能参与运算,所以得把字符(串)类型的数据转换为数值类型的数据。
(3)、四则运算时,括号优先级高于乘除,乘除优先级高于加减,程序必须能正确判断其优先级才能得出正确的结果。
(4)、为了保证运行结果的精确度需正确选择所用变量的数据类型。
2、利用所学知识进一步分析以上内容;
(1)、利用gets函数输入表达式,例如:gets(calc);
(2)、C语言中将字符类型数据转化成数值类型数据方法很多,该程序利用函数库stdlib.h中的atof函数来实现这一目的。同时注意主函数前加上预处理指令:#include<stdlib.h>。
(3)、为了能正确判断优先级,该程序利用函数间的多层嵌套,循环调用来实现;从优先级最高的括号开始判断,若有括号,再判断括号内部,若无括号判断是否为乘除,最后判断加减;括号内内容法方类似。具体判断方法在后面将以实例详细介绍。
(4)、为了保证输出数据的精确度,该程序中函数f1()-f4()返回值均用double类型;用g格式符输出最终结果让输出结果简明而又能保证其精确度。
3、开始编程:
首先编写必要的预处理指令,声明必要的函数,定义必要的变量。
#include<stdio.h> (输入,输出函数需要该指令);
#include<stdlib.h> (atof函数需要该指令);
全局声明:
Double f1(); (用于存放最终输出结果);
Char calc[n]; (用于存放输入的表达式);
Int n; (用于标注clac中的各个元素);
编写主函数:
int main(void)
{
printf("请输入表达式:\n");
gets(calc);(输入表达式)
printf("原式=%g\n",f1());(程序将调用f1(),并输出f1()的结果)
return(0);
}
由于四则运算先算出优先级最高的结果,并对同一优先级采用从左到右的顺序计算,所以最终的运算是对表达式进行加减运算。所以函数f1()必须对加减进行处理。所以编写如下:
double f1()
{
double t;
t=f2();(f2()用于临时表示乘除运算部分的结果)
while((calc[n]=='+')||(calc[n]=='-'))
{
switch(calc[n])
{
case '+':n++,t=t+f2();break;
case '-':n++,t=t-f2();break;
}
}
return(t);
}
编写f2()用于计算乘除运算,同理要使用循环:
double f2()
{
double t;
t=f3();(用于临时表示括号内部的计算结果)
while((calc[n]=='*')||(calc[n]=='/'))
{
switch(calc[n])
{
case '*':n++,t=t*f3();break;
case '/':n++,t=t/f3();break;
}
}
return(t);
}
编写f3():
double f3()
{
char a[64];(用于转存变量calc)
int i=0;
double t;
if(calc[n]=='(')
{
n++,t=f1(),n++;
}
else if(f4())
{
while(f4())(判断是否满足f4(),若满足则依次将字符转存于函数a中)
{
a[i++]=calc[n++];
}
t=atof(a);(将字符串转换为浮点数)
}
return(t);
}
编写函数f4():
ouble f4()
{
if((calc[n]>='0'&&calc[n]<='9')||(calc[n]=='.'))
return(1);
}
4、运用举例:
下面以表达式:41+2*(5-3)为例详细分析程序的运行过程:
1输入字符串41+2*(5-3)-2输出时遇到函数f1()-3调用函数f1()-4调用函数f2()-5调用函数f3()-6判断第一个字符不为’(‘,再判断第一个字符是否满足函数f4(),满足条件并判断第二个字符(满足),再判断第三个字符(不满足);将‘41’赋值个变量a,再将变量a转换成double类型赋值个变量t,将函数值41返回给该函数。-7将41返回调用处即f2()中的“t=f3()”,这时f2()返回值为41再返回f1()中的“t=2()”处。-8判断下一个字符‘+’(满足条件)执行到语句:case '+':n++,t=t+f2();-9再次调用函数f2().f3().f4().最终将‘2’返回到t=f3();处。-10判断下一字符是否为*或/,满足执行到:case '*':n++,t=t*f3();-11再次调用f3(),执行到:n++,t=f1(),n++;---------,以下调用方法类似,不再一一列出.
5、程序分析:
(1)、从函数f4()可知,输入函数calc的第一个字符必须为’.’或’0’~’9’这十个字符,否则程序终止运行,并输出错误结果。
(2)、从函数f3()可知,字符’(‘后面应紧跟数字,小数点或字符’(‘,否则出现(1)中同样的错误。例如:2+5*(-5+8)不能算出正确值。
(3)、该函数没有对字符’)’进行判断,一切为不满足函数f4()和’+’、’-‘、’*’、’/’的字符程序都将首先算出字符’(‘到该字符之间的表达式的结果;例如:2*(6+4相当于
2*(6+4)。6*(21-9m相当于6*(21-9)。
(4)、只要输入规范的数学表达式,程序都会输出正确的结果。
三、实验总结:
通过该实验我们熟悉的掌握了函数:if,while,switch等函数的格式及功能。熟悉了函数间的调用过程及相关注意事项。
四、附录 源代码
#include<stdio.h>
#include<stdlib.h>
double f1(),f2(),f3(),f4();
char calc[64];
int n;
double f1()
{
double t;
t=f2();
while((calc[n]=='+')||(calc[n]=='-'))
{
switch(calc[n])
{
case '+':n++,t=t+f2();break;
case '-':n++,t=t-f2();break;
}
}
return(t);
}
double f2()
{
double t;
t=f3();
while((calc[n]=='*')||(calc[n]=='/'))
{
switch(calc[n])
{
case '*':n++,t=t*f3();break;
case '/':n++,t=t/f3();break;
}
}
return(t);
}
double f3()
{
char a[64];
int i=0;
double t;
if(calc[n]=='(')
{
n++,t=f1(),n++;
}
else if(f4())
{
while(f4())
{
a[i++]=calc[n++];
}
num[i]='\0';
t=atof(a);
}
return(t);
}
double f4()
{
if((calc[n]>='0'&&calc[n]<='9')||(calc[n]=='.'))
return(1);
else
return(0);
}
int main(void)
{
printf("请输入表达式:\n");
gets(calc);
printf("原式=%g\n",f1());
return(0);
}
第二篇:C语言计算器设计
C语言计算器设计 姓名:付强 学号:200806204122 班级:材料成型与控制技术0801 系别:机械工程系
C语言程序设
设计思路:
用for语句控制程序整体的循环,使用后缀表达式和中缀表达式实现对运算符优先级的判断和运算。
中缀表达式:我们平时书写的表达式就是中缀表达式,形如(a+b)*(c+d),事实上是运算表达式形成的树的中序遍历,特点是用括号来描述优先级。
后缀表达式:也叫逆波兰表达式,事实上是算数表达式形成的树的后序遍历。中缀表达式(a+b)*(c+d)的后缀表达式是ab+cd+*,它的特点就是遇到运算符就立刻进行运算。
下面以一个实例来进行说明:2+(50-6*7)/2
1. 输入表达式2+(50-6*7)/2,先进行一次判断,如果为q则退出
整个程序,这里将表达式存入字符型数组a[ ]中,则a[ ]={'&','2','+','(','5','0','-','6','*','7',') ','/','2','\0'},然后调用calcu( )函数。
2. 第一次循环对a[1]进行判断,然后将2放入data[0].d1中,
nibo[1]=1;
第二次循环对a[2]进行判断,将'+'放入stack2[1]中; 第三次循环对a[3]进行判断,将'('放入stack2[2]中; 第四次循环对a[3]进行判断,先得出z=50,然后判断a[5]=0,则将'50'放入data[1].d1中,nibo[2]=2;
第五次循环对a[6]进行判断,将'-'放入stack2[3]中; 第六次循环对a[7]进行循环,将'6'放入data[2].d1中,nibo[3]=3;
第七次循环对a[8]进行判断,将'*'放入stack2[4]中; 第八次循环对a[9]进行判断,将'7'放入data[3].d1中,nibo[4]=4;
第九次循环对a[10]进行判断,将')'放入stack2[5]中; 第十次循环对a[11]进行判断,将'/'放入stack2[6]中; 第十一次循环对a[12]进行判断,然后将2放入data[4].d1中,nibo[5]=5;
第十二次循环对a[13]进行判断,为'\0',结束while循环,跳入下一个while。此时t1=6,t2=6。
具体数值如下:
nibo[++t1] Stack2[t2] data[top].d1 data[top].d2=cnt nibo[1]=1 Stack2[1]= '+' data[1].d1=2 data[1].d2=1 nibo[2]=2 Stack2[2]= '(' data[2].d1=50 data[2].d2=2 nibo[3]=3 Stack2[3]= '-' data[3].d1=6 data[3].d2=3 nibo[4]=4 Stack2[4]= '*' data[4].d1=7 data[4].d2=4 nibo[7]=5 Stack2[1]= '+' data[5].d1=2 data[5].d2=5 nibo[8]='\0' Stack2[2]= '/'
3. 进行转换,即:
nibo[8]=Stack2[2]=='+'
nibo[9]=Stack2[1]=='/'
nibo[10]='\0'
4. 进行逆波兰运算
while(j<=t1)
{ if(nibo[j]>='0'&&nibo[j]!='^'&&nibo[j]!='#')
{ for(i=1;i<=tree->top;i++)
{ if((int)(nibo[j]-'0')==tree->data[i].d2)
}
Stack3[++t3]=tree->data[m].d1;
}
else if(nibo[j]=='+')
{ Stack3[t3-1]=Stack3[t3-1]+Stack3[t3];
t3--;
}
else if(nibo[j]=='-')
{
}
else if(nibo[j]=='*')
{ } Stack3[t3-1]=Stack3[t3-1]*Stack3[t3]; t3--; Stack3[t3-1]=Stack3[t3-1]-Stack3[t3]; t3--; { } m=i; break;
else if(nibo[j]=='/')
{ Stack3[t3-1]=Stack3[t3-1]/Stack3[t3]; t3--;
}
else if(nibo[j]=='^')
{ Stack3[t3-1]=pow(Stack3[t3-1],Stack3[t3]); t3--;
}
else if(nibo[j]=='#')
{
j++;
} Stack3[t3]=sqrt(Stack3[t3]);}
5. 执行结果如图:
源程序代码:
#include<stdio.h>
#include<math.h>
#include<malloc.h>
#define M 100
double calcu(char a[]);
void main()
{
{ //负责计算的函数 int e,f; for(e=0;e<=79;e++) printf("*");
printf(" 姓名:付强 学号:200806204122 日期:2010/5/20 指导教师:陶斌 \n");
for(f=0;f<=79;f++) printf("*");
printf("\n");
printf("说明: 输入表达式时无需输入 = 号 直接回车可输出答案 \n"); printf(" 开方用 # 表示,乘方用 ^ 表示。 退出请输入q (支持负数) \n\n\n");
} //图形输出函数 for(;;) {
printf("请输入您要计算的表达式:\n"); char x, a[M]; double outcome; int i=0; a[0]='$'; scanf("%c",&x); if(x=='q') break; while(x!='\n') { a[++i]=x; scanf("%c",&x); } a[i+1]='\0';
outcome=calcu(a);
算
} //调用calsu()来进行计if(outcome==10000000000000000000) ; else printf("=%lf",outcome); printf("\n\n\n");
}
double calcu(char a[])
{
//printf("t1 nibo[t1] nibo[5] cnt (t1+1) t2 Stack2[t2]\n"); /////***** int i=1,j,k,m,cnt=0,t1=0,t2=0,t3=0;
//建立2数组 stack2. stack3用于 char nibo[50],Stack2[50];
存放算式中的数字和运算符,进行压栈
double x,n,l,z=0,Stack3[50]; typedef struct { double d1; int d2;
}dd; typedef struct
成员
{
int top; //建立结构体stack1,其中有两个dd data[50]; }Stack1; Stack1 *tree; //将stack1 指向tree的指针,在
动态内存中开辟一个stack大小的内存,并将首地址传给tree指针 tree=(Stack1 *)malloc(sizeof(Stack1));
tree->top=0;
if(a[1]=='\0'||(a[1]>='A'&&a[1]<='z')||a[1]==' ')
检查,如果出现错误则会出现提示
{ printf(" //将算式进行简单的!!!!!请输入正确的表达式!!!!!"); return(9999999999999999999);
}
else
{
while(a[i]!='\0')
字和运算符进行识别,并压入对应的栈的位置
{
if(a[i]>='0'&&a[i]<='9')
{ z=0;
j=i+1;
while(a[j]>='0'&&a[j]<='9')
{j++;}
j--;
for(k=i;k<=j;k++)
{
z=z*10+a[k]-'0';
}
j=j+1;
x=z;
if(a[j]=='.')
{
l=1;
i=j+1;
j=i+1;
while(a[j]>='0'&&a[j]<='9')
{j++;}
j--;
for(k=i;k<=j;k++)
{
n=pow(0.1,l);
l=l+1;
x=x+n*(a[k]-'0');
}
i=j+1;
}
else i=j;
tree->data[++tree->top].d1=x; 这个while循环将表达式中的数 //
tree->data[tree->top].d2=++cnt; nibo[++t1]='0'+tree->data[tree->top].d2; nibo[t1+1]='\0'; } else if(a[i]=='(') { Stack2[++t2]=a[i]; // 用tree指向的内存空间对算是的数字和运算符进行缓存,并将运算符放到后缀表达式nibo[]中
i++;
} else if(a[i]==')') { } j=t2; while(Stack2[j]!='(') { } nibo[++t1]=Stack2[j]; nibo[t1+1]='\0'; j--; t2=j-1; i++; else if(a[i]=='+') { while(t2>0&&Stack2[t2]!='(') { nibo[++t1]=Stack2[t2]; nibo[t1+1]='\0'; t2--; } Stack2[++t2]=a[i]; i++; } else if(a[i]=='-') { if(a[i-1]=='$') { } { a[i-1]='0'; a[i-2]='('; a[0]='0'; i=0; else if(a[i-1]=='(')
i=i-2; t2--; } else { } while(t2>0&&Stack2[t2]!='(') { } nibo[++t1]=Stack2[t2]; nibo[t1+1]='\0'; t2--; Stack2[++t2]=a[i]; i++; } else if(a[i]=='*'||a[i]=='/')
{ //判断是否为乘除,则放到nibo[]
while(Stack2[t2]=='*'||Stack2[t2]=='/'||Stack2[t2]=='^'||Stack2[t2]=='#') } { } nibo[++t1]=Stack2[t2]; nibo[t1+1]='\0'; t2--; Stack2[++t2]=a[i]; i++; else if(a[i]=='^'||a[i]=='#') { } while(Stack2[t2]=='^'||Stack2[t2]=='#') { nibo[++t1]=Stack2[t2]; nibo[t1+1]='\0'; t2--; } Stack2[++t2]=a[i]; i++; //printf("%d %c %d %d %d %d %c \n /////***** //printf("%c\n",nibo[5]);////////// } ",t1,nibo[t1],nibo[5],cnt,(t1+1),t2,Stack2[t2]);
while(t2>0)
{
} nibo[++t1]=Stack2[t2]; nibo[t1+1]='\0'; t2--; //printf(" %d %c\n",t1,nibo[t1]);
j=1;t3=0;
while(j<=t1)
{ //用stack3来存放运算结果,并返回到主函数为最终的值 if(nibo[j]>='0'&&nibo[j]!='^'&&nibo[j]!='#') //对后缀表达式进行出栈排列
{
}
//若nibo[]中遇到运for(i=1;i<=tree->top;i++) { if((int)(nibo[j]-'0')==tree->data[i].d2) { m=i; break; } } Stack3[++t3]=tree->data[m].d1; else if(nibo[j]=='+')
算符,则立刻进行预算,
{ } Stack3[t3-1]=Stack3[t3-1]+Stack3[t3]; t3--;
else if(nibo[j]=='-') { Stack3[t3-1]=Stack3[t3-1]-Stack3[t3]; t3--; } else if(nibo[j]=='*') { } Stack3[t3-1]=Stack3[t3-1]*Stack3[t3]; t3--;
else if(nibo[j]=='/') { } Stack3[t3-1]=Stack3[t3-1]/Stack3[t3]; t3--; else if(nibo[j]=='^') { Stack3[t3-1]=pow(Stack3[t3-1],Stack3[t3]); t3--; } else if(nibo[j]=='#') { } Stack3[t3]=sqrt(Stack3[t3]); j++;
}
return Stack3[t3]; }
}