EvaluateExpression 2.0

因为char类型越界了,表达式求值都是int类型的,所以我的策略就是定义两种类型的栈,OPTR是运算符栈,指向char类型,OPND是运算数栈,指向int类型,最后EvaluateExpression函数返回的是表达式求值的结果,返回的是int类型,所以就算返回168,也是可以存储的,不会溢出,但是不能都是char类型的,然后用int类型的接受,因为那样,char类型本身就会溢出,使用int后还是错误的数据。


#include<stdio.h>
#include<stdlib.h>
#define OVERFLOW -2
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10

typedef char cElemType;
typedef int ElemType;

typedef int Status;

typedef int OperandType;
typedef char OperatorType;

typedef struct
{
    ElemType *base;
    ElemType *top;
    int stacksize;
}SqStack;

typedef struct
{
    cElemType *base;
    cElemType *top;
    int stacksize;
}cSqStack;

Status InitStack(SqStack *S)
{
    (*S).base=(ElemType *)malloc(STACK_INIT_SIZE*sizeof(ElemType));
    if(!(*S).base)  exit(OVERFLOW);
    (*S).top=(*S).base;
    (*S).stacksize=STACK_INIT_SIZE;
    return OK;
}

Status InitcStack(cSqStack *S)
{
    (*S).base=(cElemType *)malloc(STACK_INIT_SIZE*sizeof(cElemType));
    if(!(*S).base)  exit(OVERFLOW);
    (*S).top=(*S).base;
    (*S).stacksize=STACK_INIT_SIZE;
    return OK;
}

Status Gettop(SqStack S,ElemType *e)
{
    if(S.top==S.base) return ERROR;
    *e=*(S.top-1); return OK;
}

Status cGettop(cSqStack S,cElemType *e)
{
    if(S.top==S.base) return ERROR;
    *e=*(S.top-1); return OK;
}

OperandType GetTop(SqStack S)
{
    ElemType e;
    Gettop(S,&e);
    return e;
}

OperatorType cGetTop(cSqStack S)
{
    cElemType e;
    cGettop(S,&e);
    return e;
}

Status Push(SqStack *S,ElemType e)
{
    if(((*S).top-(*S).base)>=(*S).stacksize)
    {
        (*S).base=(ElemType *)realloc((*S).base,(STACK_INIT_SIZE+STACKINCREMENT)*sizeof(ElemType));
        if(!(*S).base) exit(OVERFLOW);
        (*S).stacksize+=STACKINCREMENT;
        (*S).top=(*S).base+(*S).stacksize;
    }
    *((*S).top++)=e;
    return OK;
}

Status cPush(cSqStack *S,cElemType e)
{
    if(((*S).top-(*S).base)>=(*S).stacksize)
    {
        (*S).base=(cElemType *)realloc((*S).base,(STACK_INIT_SIZE+STACKINCREMENT)*sizeof(cElemType));
        if(!(*S).base) exit(OVERFLOW);
        (*S).stacksize+=STACKINCREMENT;
        (*S).top=(*S).base+(*S).stacksize;
    }
    *((*S).top++)=e;
    return OK;
}

Status Pop(SqStack *S,ElemType *e)
{
    if((*S).base==(*S).top) return ERROR;
    *e=*(--(*S).top);
    return OK;
}

Status cPop(cSqStack *S,cElemType *e)
{
    if((*S).base==(*S).top) return ERROR;
    *e=*(--(*S).top);
    return OK;
}

Status In(char c)  //只会对字符进行判断 应该不会越界
{
    switch(c)
    {
    case '+':
    case '-':
    case '*':
    case '/':
    case '(':
    case ')':
    case '#':
        return TRUE;
        break;
    default:
        return FALSE;
        break;
    }
}

OperandType Operate(OperandType a,OperatorType c,OperandType b)
{
    int x,y;  //0的ascii码是48

    //这是错误的写法 如果是数字0-9那么没有问题 但是这里是可能14 20就不能这样了
    //x=a-'0';
    //y=b-'0';

    x=a-48;
    y=b-48;
    //直接用数字是没有问题的

    switch(c)
    {
    case '+':
        return x+y+48;
        break;
    case '-':
        return x-y+48;
        break;
    case '*':
        return x*y+48;
        break;
    case '/':
        return x/y+48;
        break;
    }

}

OperatorType Precede(OperatorType e1,OperatorType e2)    //数据结构p53页表格
{
    OperatorType f;

    switch(e2)
    {
    case '+':
    case '-':
        if(e1=='('||e1=='#')
            f='<';
        else f='>';
        break;

    case '*':
    case '/':
        if(e1=='*'||e1=='/'||e1==')')
            f='>';
        else f='<';
        break;

    case '(':
        if(e1==')')
           {
               printf("括号匹配错误\n");
               exit(-1);
           }
        else f='<';
        break;

    case ')':
        switch(e1)
        {
        case '(':
            f='=';
            break;

        case '#':
             printf("输出了错误的括号\n");
             exit(-1);
             break;

        default:
            f='>';
            break;
        }
        break; //刚开始这里忘记了break

    case '#':
        switch(e1)
        {
        case '#':
            f='=';
            break;

        case '(':
             printf("括号匹配错误\n");
             exit(-1);
             break;

        default:
            f='>';
            break;
        }
        break; //case中的break只跳出小switch,在这种情况下会继续向大switch下比较

    }

    return f;

}

OperandType EvaluateExpression(char *exp)
{
    cSqStack OPTR;  //运算符栈
    InitcStack(&OPTR);
    cPush(&OPTR,'#');

    SqStack OPND;  //运算数栈
    InitStack(&OPND);

    char ch;
    int i=0;
    ch=exp[i++];

    OperandType a,b;  //运算数类型
    OperatorType c,e;   //运算符类型

    while(ch!='#'||cGetTop(OPTR)!='#') //刚开始这里符号错误处理成了&&根本进不了循环 直接返回的就是#的ascii码是35   //GetTop(OPTR)!='#'是避免第一个数输入的就是运算符
    {
        if(!In(ch))
        {
            Push(&OPND,ch);
            ch=exp[i++];
        }
        else
        {
            switch(Precede(cGetTop(OPTR),ch))
            {
            case '<':
                cPush(&OPTR,ch);
                ch=exp[i++];
                break;

            case '=':
                cPop(&OPTR,&e);
                ch=exp[i++];
                break;

            case '>':                      //这里没有输入字符,保留的是刚刚的字符
                cPop(&OPTR,&c);
                Pop(&OPND,&b);
                Pop(&OPND,&a);
                Push(&OPND,Operate(a,c,b));  //这个地方顺序不能反  比如5-6哈 存进去是5 6 出来应该是6 5
                break;
            }
        }
    }

    return GetTop(OPND);

}

//#include<stdio.h>
//int main()
//{
//    char c=168;
//    printf("%d",c-48);
//    return 0;
//}
//
//-136
//Process returned 0 (0x0)   execution time : 0.196 s
//Press any key to continue.
//
//分析如下:
//c语言的char类型只有一个字节,默认的char是有符号字符型,取值范围是-128~127
//定义char是168的话,越界了,会做如下处理
//168是正数,原码是10101000,而计算机是按照补码形式计算存储的,正数的补码等于原码,所以存在计算机里的是10101000
//计算机在读取的时候,最高位被当作符号位,因为最高位是1,所以就是负数,又因为补码形式计算存储,求原值求原码
//负数的原码等于补码的补码,所以就是符号位不变,其他位取反末位加一,11011000,最高位1换算成-号,结果就是-88
//在输出的时候又是c-48,所以结果就是-88-48=-136
//
//#include<stdio.h>
//int main()
//{
//    char c=128;
//    printf("%d",c);
//    return 0;
//}
//
//-128
//Process returned 0 (0x0)   execution time : 1.562 s
//Press any key to continue.
//
//分析如下:
//
//那么-128,其原码为1 (符号位)10000000,符号位不变,其他位求反后末尾加一,求得补码为1(符号位) 10000000,由于char类型一个字节,只能存储8位,存储后为10000000
//
//读取时,因为首位是1,为负数,所以其他位按位求反再加一,结果为10000000,为128,所以为-128
//
//128是正数,补码等于原码为10000000,存储在计算机中,因为这个等于-128的补码,所以输出为-128
//
//总结:
//
//1.把原本的数转换成二进制,求取补码,溢出后截取符合的位数,存储在计算机中
//
//2.读取的时候,按照最高位是符号位,再根据对应的符号,对数值进行相应的处理,读取数据

int main()
{
    int n;
    char *exp="3*(7-2)*8*9-7#";  //因为我输入的时候输入完#号后没有结果,所以我采用的这种方法,只需要将函数中的ch=getchar();换成ch=exp[i++]
    n=EvaluateExpression(exp);
    printf("作为示例,%s 的计算结果为:%d\n",exp,n-48);
    return 0;

    //char *exp = "(2+3)*4*6#";
    //这个的输出结果一直都是-136,奇奇怪怪
    //我当时的想法就是120+48后是168 超过了128范围 所以出错了

    //char *exp="3*(7-2)*9#";
    //这个结果是-121 本来结果应该是135 135+|-121|=256

    //char *exp="3*(7-2)*8#";
    //这个结果是-136 本来结果是120  120+|-136|=256

    //据我验证 128后就不能输出 在此之前是加上了48 所以超过80 就输出错误  输出的是  原本的答案-256
    //char *exp="9*9#" 就是81-256=-175

}

//#include<stdio.h>
//int main()
//{
//    int a=168;
//    printf("%c",a);
//    return 0;
//}

//127的ascii码 在控制台输出时我没有看到 但是复制粘贴输出结果的时候出现了这个 太神奇了吧
//
//Process returned 0 (0x0)   execution time : 1.412 s
//Press any key to continue.

//128的ascii码 我居然在控制台看到了这样原封不动的样子
//€
//Process returned 0 (0x0)   execution time : 0.105 s
//Press any key to continue.

//129的时候就没有输出了
//Process returned 0 (0x0)   execution time : 0.099 s
//Press any key to continue.



测试结果:

作为示例,3*(7-2)*8*9-7# 的计算结果为:1073

Process returned 0 (0x0)   execution time : 1.379 s
Press any key to continue.

发布了34 篇原创文章 · 获赞 38 · 访问量 2651

猜你喜欢

转载自blog.csdn.net/qq_43779149/article/details/104195080