C语言表达式求值Word文档格式.docx
《C语言表达式求值Word文档格式.docx》由会员分享,可在线阅读,更多相关《C语言表达式求值Word文档格式.docx(19页珍藏版)》请在冰豆网上搜索。
![C语言表达式求值Word文档格式.docx](https://file1.bdocx.com/fileroot1/2022-12/31/9cdde03e-0994-43e0-a806-ee0496ea60c2/9cdde03e-0994-43e0-a806-ee0496ea60c21.gif)
算符优先关系矩阵
3、算符表示
为了使算符与优先关系矩阵的行列号对应,把表达式中可能有的算符放入一维数组中,可以用字符在一维数组中的下标作为字符的标识码。
本计算中,算法表示如下:
+
-
*
/
(
)
+
0123456
即用0表示算符“+”,用1表示算符“-”,等。
定义的字符数组为:
chara[]={'
+'
'
-'
*'
/'
('
)'
#'
};
4、优先关系矩阵的表示
大于关系用1表示
小于关系用-1表示
等于关系用0表示
若两个算符间不存在关系,则用一个特定的数值表示,如用整数的上限值32767表示,可定义一个宏常量来表示:
#defineNO32767
则其优先关系矩阵为:
intPriorityTable[7][7]={{1,1,-1,-1,-1,1,1},
{1,1,-1,-1,-1,1,1},
{1,1,1,1,-1,1,1},
{1,1,1,1,-1,1,1},
{-1,-1,-1,-1,-1,0,NO},
{1,1,1,1,NO,1,1},
{-1,-1,-1,-1,-1,NO,0}
};
5、算术表达式求值算法的实现原理
处理过程:
设置两个栈:
操作数栈OPND和运算符栈OPTR。
1、首先置操作数栈为空栈,把“#”移进运算符栈(实际放入栈中的是字符“#”在字符数组中的下标,对其它算符也是一样)。
2、从左至右扫描表达式,凡遇到操作数一律进OPND栈;
若遇到运算符,则把栈顶运算符与扫描运算符的优先数进行比较:
若
-1:
扫描运算符进OPTR栈
0:
若“(”和“)”,栈顶符号出栈;
若为#,运算结束。
1:
取OPND栈顶操作数与OPTR栈顶算符进行运算,参与运算的操作数和运算符出栈,运算结果进OPND栈
NO:
表示表达式有错。
若表达式处理完,OPTR栈为#,OPND栈中只剩一项,表示表达式的运算结果,则分析成功。
若达不到这种状态,表明表达式有错。
五、实现
1、数据存储结构
假设一个表达式不可能很长,如不超过屏幕上一行的宽度(80个字符),在对表达式处理之前先把表达式放入一个一维字符数组中,用户可以不输入表达式前后的“#”,由处理程序自动加入。
由于表达式的长度有限,运算符栈和操作数栈的长度野优先,假定不超过20,所以都采用顺序存储结构比较合适。
用C语言可定义如下:
#defineEXPLENGT100
#defineSTACKSIZE20
charexpr[EXPLENGT];
intOPTR[STACKSIZE];
//运算符栈,元素为运算符对应的整数编码
doubleOPND[STACKSIZE];
//操作数栈,元素为表达式中的运算数据
2、运算符宏定义
为了判断运算符的方便,增强程序的可读性,定义如下宏常量:
#definePLUS0//运算符+
#defineMINUS1//运算符-
#definePOWER2//运算符*
#defineDIVIDE3//运算符/
#defineLEFTP4//运算符(
#defineRIGHP5//运算符)
#defineSTARTEND6//运算符#
#defineDIGIT7//数字字符
#definePOINT8//小数点
3、基本功能
(1)输入算术表达式
(2)计算表达式的值
4、辅助功能
(1)菜单选择
(2)获取字符类型编码
5、程序结构
该程序由5个函数组成,其中主函数1个,基本功能函数2个,辅助功能函数2个。
函数间的调用关系图1所示。
图1程序结构图
6、函数说明
(1)主函数main
功能:
根据菜单选择确定要操作的内容:
表达式输入
表达式计算
计算结果输出
退出系统
(2)菜单选择函数:
menu
功能:
构造功能菜单,并选择下一步要操作的功能。
格式:
intmenu(void)
参数:
无参数。
返回值:
1~4中的一个序号。
可供选择的功能如下:
1--inputexpression表示输入表达式
2--calculationexpression表示计算表达式
3--printresult表示输出计算结果
4--Quit表示退出系统,结束程序的运行
(3)表达式输入函数:
InputExpression
输入表达式,并在表达式前后加上符号“#”
voidInputExpression(charstr[])
参数:
charstr[]—存放输入的表达式
无
(4)表达式计算函数:
excute
功能:
完成表达式的计算
intexcute(char*str,double*Result)
char*str—要计算的表达式字符串
double*Result—计算结果值
返回值:
1—计算成功
0—计算失败
(5)确定当前字符类型函数:
GetCharType
确定当前要处理的字符的类型
intGetCharType(charch)
charch—当前要处理的字符
若为算符,返回字符的编码(一维数组下标)
若为数字,返回符号常熟DIGIT(数字)
若为小数点,返回符号常熟POINT(小数点)
若不是定义的表达式的字符,返回-1。
六、算法描述
1、表达式计算算法描述
设栈顶指针:
inttopTr—运算符栈顶指针
topNd—操作数栈顶指针
表达式字符指针:
intpp—指向表达式中当前要处理的字符
开始时,把表达式开始符“#”(编码)放入栈中。
设当前要处理的字符类型为CharType。
以当前要处理的字符为参照来确定下一步要作的处理:
●若当前字符为非法字符:
则结束处理,返回出错标志(0);
●若当前字符是数字:
表示遇到表达式中的操作数,则识别出该操作数;
●若当前字符是小数点:
表示遇到以小数点开头的操作数,则识别出该操作数;
●若当前字符是+、-、*、/运算符:
则用栈顶运算符与当前运算符比较优先性:
若对应的数组元素为-1,则当前运算符(运算符编码)进栈,调整pp指向下一个字符。
若对应的数组元素为1,则取运算符栈顶运算符和操作数栈顶操作数进行运算,参与运算的运算符和操作数出栈,运算结果进操作数栈。
实现为:
OPND[topNd-2]=OPND[topNd-2]opOPBD[topNd-1];
topNd--;
topTr--;
●若当前字符是左括号(:
则左括号进栈,pp指向下一个字符
●若当前字符是右括号):
⊙若栈顶是左括号,则左括号出栈,pp指向下一个字符
⊙若栈顶是运算符,则取运算符栈顶运算符和操作数栈顶操作数进行运算,参与运算的运算符和操作数出栈,运算结果进操作数栈。
重复该操作,直到栈顶出现左括号“(”。
⊙若栈顶是#,则左括号和右括号不配对,结束处理,返回出错标志(0)
●若当前字符为#:
依次从运算符栈取出运算符和从操作数栈取出操作数进行计算,直到运算符栈的栈顶为#为止。
若运算符栈顶为#,当前字符也为#,则表达式计算结束,返回计算结果值和计算成功标志
(1)。
2、字符型数字常数转换为数值型常数的方法
因为程序处理的表达式是以字符串形式出现的,表达式中每个数值型常数也是有一个一个的数字字符组成。
处理程序必须把字符串形式的常数转换为数值形式的常数。
(1)整数的转换方法
我们知道,一个数值型常数3256可以表示为:
3256=((3*10+2)*10+5)*10+6
相应的,一个字符串型的数字常数“3256”转换为数值型常数可以表示为:
(((‘3’-48)*10+(‘2’-48))*10+(‘5’-48))*10+(‘6’-48)
每个字符的ASCII码指减去48就是该字符对应数字值。
实现方法:
依次读入数字字符,用前面读入子字符串对应的数值型值乘以10,再加上当前字符的数字值,就是当前读入子字符串对应的数值型值。
用C语言描述如下:
number=0;
while(str[pp]>
='
0'
&
&
str[pp]<
9'
)
{number=number*10+(str[pp]-48);
pp++;
}
(2)小数的转换方法
一个小数常数0.2345可以表示为:
0.2345=2/10+3/100+4/1000+5/10000
相应的,一个字符串表示的小数“0.2345”转换为数值型小数可以表示为:
“0.2345”=(‘2’-48)/10+(‘3’-48)/100+(‘4’-48)/1000+(‘5’-48)/10000
假设当前字符指针指向小数点字符,转换方法描述为:
temp=10.0;
pp++;
{number=number+(str[pp]-48)/temp;
temp=temp*10;
(3)既有整数又有小数部分的实数的转换算法
综合前面两部分算法,既有整数又有小数部分的实数的转换算法描述如下:
while(str[pp]>
)//处理实数的整数部分
}
if(str[pp]=='
.'
)//遇到小数点
{temp=10.0;
)//处理实数的小数部分
{number=number+(str[pp]-48)/temp;
temp=temp*10;
七、思考题
1、若表达式中的数据带有正负号的实数字符串该怎样进行转换?
2、对于指数形式的实数字符串该怎样进行转换?
八、部分函数代码
#include<
stdio.h>
#include<
string.h>
conio.h>
#definePLUS0
#defineMINUS1
#definePOWER2
#defineDIVIDE3
#defineLEFTP4
#defineRIGHP5
#defineSTARTEND6
#defineDIGIT7
#definePOINT8
#defineNUM7
#defineNO32767
//运算符
chara[]={'
//优先关系矩阵,规定:
=为0,>
为1,<
为-1,空为NO
intPriorityTable[7][7]={{1,1,-1,-1,-1,1,1},
{1,1,-1,-1,-1,1,1},
{1,1,1,1,-1,1,1},
{1,1,1,1,-1,1,1},
{1,1,1,1,NO,1,1},
{-1,-1,-1,-1,-1,NO,0}
intmenu(void);
/*{
intn;
printf("
\n\n"
);
MENU\n"
********************************************\n"
operations\n"
1.输入表达式\n"
2.计算表达式\n"
3.输出计算结果\n"
4.退出\n"
choice(1,2,3,4):
"
scanf("
%d"
&
n);
returnn;
}*/
/***************************/
/*输入表达式函数*/
{intlen;
Inputexpressionstring:
\n"
%s"
str);
len=strlen(str);
str[len]='
;
str[len+1]='
\0'
/*************************************************/
/*确定当前字符类型*/
/*若为运算符,则返回运算符在运算符数组中的序号*/
/*若为数字字符,则返回DIGIT*/
/*若为小数点字符,则返回POINT*/
/*否则为非法字符,返回-1*/
{inti;
for(i=0;
i<
NUM;
i++)if(ch==a[i])return(i);
if(ch>
ch<
)return(DIGIT);
if(ch=='
)return(POINT);
return(-1);
/*表达式计算*/
/*输入参数:
char*str,表达式字符串*/
/*输出参数:
double*Result,表达式计算结果*/
/*函数返回值:
1计算正确*/
/*0表达式有错*/
intEXCUTE(char*str,double*Result)
{
intpp,strlength,topTr,topNd,CharType,OPTR[STACKSIZE];
intb,c;
char*p;
doublenumber,temp,OPND[STACKSIZE];
OPTR[0]=STARTEND;
topTr=1;
topNd=0;
pp=0;
while((str[pp]))
{CharType=GetCharType(str[pp]);
//确定字符类型
switch(CharType)
{case-1:
//不是表达式中的字符,表达式有错
return(0);
caseDIGIT:
//数字字符,实数的开始字符
number=0;
if(str[pp]=='
while(str[pp]>
OPND[topNd]=number;
topNd++;
break;
casePOINT:
//小数点,以小数点开头的实数
casePLUS:
//+
caseMINUS:
//-
casePOWER:
//*
caseDIVIDE:
///
while(PriorityTable[OPTR[topTr-1]][CharType]==1)
{
if(OPTR[topTr-1]==PLUS)
number=OPND[topNd-2]+OPND[topNd-1];
elseif(OPTR[topTr-1]==MINUS)
number=OPND[topNd-2]-OPND[topNd-1];
elseif(OPTR[topTr-1]==POWER)
number=OPND[topNd-2]*OPND[topNd-1];
elseif(OPTR[topTr-1]==DIVIDE)
number=OPND[topNd-2]/OPND[topNd-1];
topNd--;
topNd--;
topTr--;
OPND[topNd]=number;
topNd++;
returnnumber;
}
OPTR[topTr]=CharType;
topTr++;
pp++;
break;
caseLEFTP:
//(
OPTR[topTr]=LEFTP;
caseRIGHP:
//)
while(OPTR[topTr-1]!
=LEFTP)
{
number=OPND[topNd-1]+OPND[topNd-2];
topNd--;
OPND[topNd]=number;
topNd++;
returnnumber;
}
topTr--;
topTr--;
pp++;
caseSTARTEND:
//遇到表达式结束符
=STARTEND)
number=OPND[topNd-1]+OPND[topNd