⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 expc.c

📁 表达式计算器
💻 C
字号:
#include <stdio.h>
#include <math.h>
#define MAXLEN  400 //定义栈的长度
//定义运算符的值
#define OPRADD  1  
#define OPRSUB  2
#define OPRMUL  3
#define OPRDIV  4
#define OPRMOD  5 
#define OPRPOW  6 
#define OPRLP   7
#define OPRRP   8

struct strdata  //存储解析后的表达式
{
	double d;
	double (*f)();
}
;

//定义存储在结构 struct strdata中的是什么
#define ENDFLAG 255  //表示结束
#define DATAFLAG 0      //表示存储的是数据
#define OPRFLAG 1      //表示存储的是运算符
#define FUNCFLAG 2      //表示存储的是函数


#define FUNCNUM   16 //定义函数的总数目
#define FUNNAMELEN 5 //定义函数名的最长长度


extern int expcerr=0;

/*下面是表达式计算的主函数*/
double calcExp(char * ch); 

/*把表达式解析到结构data中,和数组flag中*/
void parse(char *,struct strdata * data,int * flag); 

/*把字符串形数字变成double型数字*/
double getvalue(char * ch,int * pi); 

/*计算存储在data结构和数组flag中的表达式的值*/
double calcArray(struct strdata * data,int * flag);

/*计算算符的优先级 flag=0表示栈内,flag=1表示栈外*/
int prior(double ch,int flag);  
double negate(double data);

/*两数相运算*/
double oprcalc(double data1,double data2,double opr); 
static char * expcerrmsg[8] ={"",
                          "有非法字符!",
						  "语法错误!",
						  "括号不匹配!",
						  "长度过长",
						  "被0除!",
						"函数的参数值超出范围!"};

void getfunc(struct strdata * data,char *,int *,int *);

double calcExp(char * ch)
{
  double result;
  struct strdata data[MAXLEN];
  int flag[MAXLEN];
  int i;
  expcerr=0;
  for(i=0;i<MAXLEN;i++)
	  data[i].f=NULL;

  parse(ch,data,flag);
  if (expcerr==0)
  {
     result=calcArray(data,flag);
	 return result;
  }  
  else 
	 return 0;
  return -1;
}

void parse(char * ch,struct strdata * data,int * flag)
{
  int i=0,j=0;
  char ch1;
  int v1,v2;
  ch1=*ch;
  
  
  while(ch1!='\0')
  {
    if (ch1==','|| ch1==' ')
	{
		i++;
		ch1=ch[i];
		continue;
	}


	if (ch1>=48 && ch1<=57)
    {
       flag[j]=DATAFLAG;
       data[j].d=getvalue(&ch[i],&i);
    }
    else
    {
		//判断'-'是减号还是负号
		if(ch1=='-')
		{
			if(i==0)
			{
				data[j].f=negate;
				flag[j]=FUNCFLAG;	
			}
			else
			{
				if(j==0)
				{
					data[j].d=OPRSUB;
					flag[j]=OPRFLAG;
				}
				else
				{
					if(flag[j-1]==OPRFLAG && data[j-1].d!=OPRRP)
					{
						data[j].f=negate;
						flag[j]=FUNCFLAG;	
					}
					else
					{
						data[j].d=OPRSUB;
						flag[j]=OPRFLAG;

					}

				}
		
			}
		goto end;
		}

		flag[j]=OPRFLAG;
		switch(ch1)
	   {
		   case '+':
			   data[j].d=OPRADD;
			   break;
	
		   case '*':
			   data[j].d=OPRMUL;
			   break;
		   case '/':
			   data[j].d=OPRDIV;
			   break;
		   case '%':
			   data[j].d=OPRMOD;
			   break;
	       case '^':
			   data[j].d=OPRPOW;
			   break;
		   case '(':
			   data[j].d=OPRLP;
			   break;
		   case ')':
			   data[j].d=OPRRP;
		       break;
          //如果是如果是其它字符,检查是否是函数
		   default:
			   if(j>0 )
			   {
				   //前面是数字,认为有一个*号
				   if(flag[j-1]==DATAFLAG)
				   {
					   flag[j]=OPRFLAG;
					   data[j].d=OPRMUL;
					   j++;

				   }
			   }

			   getfunc(&data[j],&ch[i],&i,&flag[j]);
			   if(expcerr!=0)
				   return ;

	   }
	} 
end:
	j++;
    i++;
	if(i>MAXLEN)
	{
		expcerr=4;
		return ;
	}

	ch1=ch[i];
  }
 
   flag[j]= ENDFLAG;
   
   //检查是否有连续有算符情况
   for(j=1;flag[j]!=ENDFLAG;j++)
   {
	   
	   if ((flag[j]==flag[j-1])==OPRFLAG)
	   {
           if (data[j].d==OPRLP)
			   v2=1;
		   else
			   if (data[j].d==OPRRP)
				   v2=2;
			   else
				   v2=0;
        
		  if (data[j-1].d==OPRLP)
			   v1=1;
		   else
			   if (data[j-1].d==OPRRP)
				   v1=2;
			   else
				   v1=0;

		   if((v1==2 && v2==1)
		   || (v1==1 && v2==2)
		   || (v1==0 && v2==2)
		   || (v1==1 && v2==0)
		   || (v1==0 && v2==0)
             )
		   {
			  expcerr=2;
			  return ;
		   }
	   }
   }

 //检查是否有左右括号数目不一致情况
   j=0;
   for(i=0;flag[i]!=ENDFLAG;i++)
   { 
	   if(flag[i]==OPRFLAG)
	   {
		   if (data[i].d==OPRLP)
			   j++;
		   else
			   if(data[i].d==OPRRP)
				   j--;

	   }
   }
   
	if (j!=0)
	{
		expcerr=3;
		return ;
   }

   return ;

}

double getvalue(char * ch,int * pi)
{
  double result,temp=10;
  result=0;
  while ((*ch)>=48 && (*ch)<=57)
  {
      result=result*10+(*ch - 48);
	  ch++;
	  (*pi)++;
  }
  if(*ch=='.')
   {
	   ch++;
	   (*pi)++;
	   while ( (*ch)>=48 && (*ch)<=57)
	   {
		   result=result + (*ch -48 )/temp;
		   temp=temp*10;
		   ch++;
		   (*pi)++;
	   }
  }

  (*pi)--;
  return result;
}

double calcArray(struct strdata * data,int * flag)
{
	int i=0,j=-1,k=-1,m=0,n=0,bz=0;
	struct strdata stackdata[MAXLEN];
	double nextopr;
	double result=0;
	
	while (1)
	{
		if (flag[i]==DATAFLAG)  //如果遇到操作数,进栈
		{
		   j++;
		   stackdata[j].d=data[i].d;
		   stackdata[j].f=NULL;
		   i++;
		   continue;
		}

		//如果遇到(,进栈
		if(flag[i]==OPRFLAG && data[i].d==OPRLP)
		{
			j++;
			stackdata[j].d=data[i].d;
			stackdata[j].f=NULL;
			i++;
			continue;
		}
        
		//如果是函数,进栈
		if(flag[i]==FUNCFLAG)
		{
			j++;
			stackdata[j].f=data[i].f;
			i++;
			continue;
		}
		//如果遇到),
		if (flag[i]==OPRFLAG
		&&  data[i].d==OPRRP)
		{
			while (1)
			{
				while(stackdata[j-1].f!=NULL) //如果是函数
				{
					stackdata[j-1].d=(* stackdata[j-1].f)(stackdata[j].d);
					stackdata[j-1].f=NULL;
					j--;
				}
				if(stackdata[j-1].d==OPRLP)
					break;

				while (stackdata[j-1].d!=OPRLP && stackdata[j-1].f==NULL)//如果是运算符
				{
					stackdata[j-2].d=oprcalc(stackdata[j-2].d,stackdata[j].d,stackdata[j-1].d);
					j=j-2;
					if (j<=0)
						break;
				}
				if(stackdata[j-1].d==OPRLP && stackdata[j-1].f==NULL)
					break;

			}
			
			//删除栈中"("和跳过data[i].d中的")"
			j--;
			stackdata[j].d=stackdata[j+1].d;
			stackdata[j].f=NULL;
			i++;
			
			if (j<=0)
				continue;

			//如果出栈后前一个是函数,继续出栈运算
			if (stackdata[j-1].f!=NULL)
				while (stackdata[j-1].f!=NULL)
				{
					stackdata[j-1].d=(* stackdata[j-1].f)(stackdata[j].d);
					stackdata[j-1].f=NULL;
					j--;
					if (j<=0)
						break;
				}
			continue;
    
		}


		//如果遇到一般操作符
		if (flag[i]==OPRFLAG 
		 && data[i].d!=OPRLP 
		 && data[i].d!=OPRRP)
		{
			//如果后面是操作符或函数,操作符入栈
			if (flag[i+1]==OPRFLAG ||flag[i+1]==FUNCFLAG )
			{
				j++;
				stackdata[j].d=data[i].d;
				stackdata[j].f=NULL;
				i++;
				continue;
			}
			else
			{
				//其后不是操作符和函数,是数值时,下一个肯定是操作符和函数
				if (data[i+2].d!=OPRRP)  //下一个不是)时,且没有结束时入栈
				{
					nextopr=data[i+2].d;
					//没有结束
					if (flag[i+2]!=ENDFLAG)
					{
						if (prior(data[i].d,0) - prior(nextopr,1) <0 )
						{
							j++;
							stackdata[j].d=data[i].d;
							stackdata[j].f=NULL;
							i++;
							continue;
						}
					}
					
					//结束或后面的优先级低于前面的出栈计算
					j++;
					stackdata[j].d=data[i].d;
					stackdata[j].f=NULL;
					i++;
					j++;
					stackdata[j].d=data[i].d;
					stackdata[j].f=NULL;
					i++;
					while (1)
					{
						if(j<=0)
							break;

						if (stackdata[j-1].f==NULL) //栈中不是函数
						{
							if (prior(stackdata[j-1].d,0) - prior(nextopr,1) >=0)
							{
								stackdata[j-2].d=oprcalc(stackdata[j-2].d,stackdata[j].d,stackdata[j-1].d);
								j=j-2;
							}
							else
								break;

						}
						else //栈中是函数
						{
						   stackdata[j-1].d=(* stackdata[j-1].f)(stackdata[j].d);
						   stackdata[j-1].f=NULL;
						   j--;
						}

					}
					continue;
				}
				else
				{//其后一个操作符是)
					j++;
					stackdata[j].d=data[i].d;
					stackdata[j].f=NULL;
					i++;
					j++;
					stackdata[j].d=data[i].d;
					stackdata[j].f=NULL;
					i++;
					while (stackdata[j-1].d!=OPRLP)
					{
						stackdata[j-2].d=oprcalc(stackdata[j-2].d,stackdata[j].d,stackdata[j-1].d);
						j=j-2;
					}
					//删除栈中(和跳过data[i].d中的)
					j--;
					stackdata[j].d=stackdata[j+1].d;
					stackdata[j].f=NULL;
					i++;
					if (j<=0)
						continue;
					//如果出栈后前一个是函数,继续出栈运算
					if (stackdata[j-1].f!=NULL)
						while (stackdata[j-1].f!=NULL)
						{
							stackdata[j-1].d=(* stackdata[j-1].f)(stackdata[j].d);
							stackdata[j-1].f=NULL;
							j--;
							if (j<=0)
								break;
						}

					continue;
				}
			}
		}

		if (flag[i]==ENDFLAG)
		{
			if(j==0)
				return stackdata[j].d;

			while (1)
			{
				if(j<=0)
					return stackdata[j].d;
				if (stackdata[j-1].f==NULL) //栈中不是函数
				{
					stackdata[j-2].d=oprcalc(stackdata[j-2].d,stackdata[j].d,stackdata[j-1].d);
					j=j-2;
				}
				else //栈中是函数
				{
					stackdata[j-1].d=(* stackdata[j-1].f)(stackdata[j].d);
					stackdata[j-1].f=NULL;
					j--;
				}
			}
		}			
	
	}
	return result;
}

int prior(double opr,int flag)
{
	int iopr=(int)opr;
	switch(iopr)
	{
	case OPRADD:
		return 1;
	case OPRSUB:
		return 1;
	case OPRMUL:
		return 2;
	case OPRDIV:
		return 2;
	case OPRMOD:
		return 2;
	case OPRPOW:
		return 3;
	case OPRLP:
		if(flag)
			return 9;
		else
			return 0;

	case OPRRP:
		if(flag)
		   return 0;
		else
		   return 9;
 
	}
   return -1;
}

double oprcalc(double data1,double data2,double opr)
{
    int iopr=(int)opr;
	switch(iopr)
	{
	case OPRADD:
		return (data1+data2);
	case OPRSUB:
		return (data1-data2);
	case OPRMUL:
		return (data1*data2);
		
	case OPRDIV:
		if (data2==0)
		{
			expcerr=6;
			return 0;

		}
		else
		{
			return (data1/data2);
		}
	case OPRMOD:
		return fmod(data1,data2);

	case OPRPOW:
		return pow(data1,data2);
    	
	}
	return 0;

}

void getfunc(struct strdata * data,char * ch,int *pi,int *pflag)
{
	int i,j,flag;
	
	char * funcname[FUNCNUM]={"abs","acos","asin"
							,"atan","cos","cosh"
							,"exp","log"
							,"log10","sin"
							,"sinh","tan","tanh"
							,"sqrt","ceil","floor"
							};

	double (*pfun[FUNCNUM])()={fabs,acos,asin
							,atan,cos,cosh
							,exp,log
							,log10,sin
							,sinh,tan,tanh
							,sqrt,ceil,floor
							};

		                      
	char temp[FUNNAMELEN+1];
    
	for(i=0;i<=FUNNAMELEN;i++)
		temp[i]='\0';

    for(i=0;ch[i]!='(' && i<=FUNNAMELEN;i++)
	{
      temp[i]=ch[i];
	}
    if (i>FUNNAMELEN)
	{
		expcerr=1;
		return ;
    }
	(*pi)=(*pi)+i-1;


    for(i=0;i<FUNCNUM;i++)
	{
		flag=1;
		for(j=0;j<=FUNNAMELEN && funcname[i][j]!='\0';j++)
		{
			if (temp[j]!=funcname[i][j])
			{
               flag=0;
			   break;
			};
		}
        if (funcname[i][j]=='\0' && temp[j]=='\0' &&flag==1)
		{
			data->f=pfun[i];
			(*pflag)=FUNCFLAG;
			break;
		}

	}
    if (i<FUNCNUM)
	{
		expcerr=0;
		return ;
   	}
	expcerr=1;
	return ;

}

double negate(double data)
{
	return -data;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -