哗啦哗啦啦啦啦 发表于 2020-12-14 12:55:17

C++,用户输入的字符数组结尾在程序运行中自动变空格,而不是'\0'

简单计算器的实现(实现整数的加减乘除)用了继承的方法,通过data和char的两个栈分别存放操作数和运算符来实现
先不看逆波兰的计算,先实现简单的1+2

//counter.cpp

#include <iostream>
#include<string.h>
#include<stdio.h>
#include "counter_char.h"
#include "counter_data.h"
using namespace std;

void append_data(char*& rpn,int opnd)//将操作数接至RPN末尾
{
        int n = strlen(rpn);//RPN当前长度(以'\0'结尾,长度n+1)
        char buf;
        sprintf(buf,"%d \0",(int)opnd);//将一个格式化的字符串输出到一个目的字符串中
        //rpn = (char*)realloc(rpn,sizeof(char)*(n+strlen(buf)+1));//扩展空间
        strcat(rpn,buf);//把buf所指向的字符串追加到rpn的末尾,RPN加长
}

void append_char(char*& rpn,char optr)//将运算符接至RPN末尾
{
        int n = strlen(rpn);////RPN当前长度(以'\0'结尾,长度n+1)
//        rpn = (char*)realloc(rpn,sizeof(char)*(n+3));//扩展空间
        sprintf(rpn+n,"%c ",optr);
        rpn = '\0';//接入指定的运算符
}

void readNumber(char*& p,Stack_data & stk)//将起始于p的子串解析为数值,并存入操作数栈
{
        stk.push((int)(*p - '0'));//当前数位对应的数值进栈
        while(isdigit(*(++p)))//只要后续还有紧邻的数字(即多位整数的情况),则
                stk.push(stk.pop()*10+(*p - '0'));//弹出原操作数并追加新位数后,新数值重新入栈
}

#define N_OPTR 5//运算符总数
typedef enum{ADD,SUB,MUL,DIV,EOE}Operator;//运算符集合
//加、减、乘、除、起始符与终止符

const char pri=//运算符优先等级[栈顶][当前]
{
        '>', '>', '<', '<', '>',
        '>', '>', '<', '<', '>',
        '>', '>', '>', '>', '>',
        '>', '>', '>', '>', '>',
        '<', '<', '<', '<', '='
};

OperType optr2rank(char op)//由运算符转译出编号
{
        cout << "op:" << int(op) << endl;
        switch(op)
        {
        case '+':return ADD;//加
        case '-':return SUB;//减
        case '*':return MUL;//乘
        case '/':return DIV;//除
        case '\0':return EOE;//起始符与终止符
        default:printf("语法错误3\n");exit(-1);//未知运算符
        }
}

char orderBetween(char op1,char op2)//比较两个运算符之间的优先级
{
        return pri;
}

int calcu(int pOpnd1,char op,int pOpnd2)//op为操作符,pOpnd1和2为操作数
{
        int result;
        switch(op)
        {
                case ADD:
                        result = pOpnd1 + pOpnd2;
                        break;
                case SUB:
                        result = pOpnd1 - pOpnd2;
                        break;
                case MUL:
                        result = pOpnd1 * pOpnd2;
                        break;
                case DIV:
                        result = pOpnd1 / pOpnd2;
                        break;
                default:printf("语法错误2\n");exit(-1);
        }
        return result;
}

float evaluate(char* S,char* RPN)//对(已删除白空格的)表达式S求值,并转换为逆波兰式RPN
{//S为存放字符数组的指针
        Stack_data opnd;
        Stack_char optr;
        optr.push('\0');//尾哨兵'\0'也作为头哨兵首先入栈
        while(!optr.empty())//在运算符栈非空之前,逐个处理表达式中各字符
        {
                if(isdigit(*S))//如果当前字符为操作符,则
                {
                        cout << "这一轮while是if" << endl;
                        cout << "*S是:" << *S << endl;
                        readNumber(S,opnd);
                        append_data(RPN,opnd.top());//读入操作数,并将其接至RPN末尾→拼成逆波兰式
                }
                else//若当前字符为运算符,则
                {
                        cout << "这一轮while是else" << endl;
                        cout << "*S是:" << *S << endl;

                        cout << "orderBetween(optr.top(),*S):" << orderBetween(optr.top(),*S) << endl;
                        switch(orderBetween(optr.top(),*S))//视其与栈顶运算符之间优先级高低分别处理
                        {
                                case'<'://栈顶运算符优先级更低时
                                        optr.push(*S);S++;//计算推迟,当前运算符进栈
                                        break;
                                case'='://优先级相等(当前运算符为右括号或尾部哨兵'\0')时
                                        optr.pop();S++;//脱括号并接收下一个字符
                                        break;
                                case'>'://栈顶运算符优先级更高时,可实施相应的计算,并将结果重新入栈
                                {
                                        char op = optr.pop();append_char(RPN,op);//栈顶运算符出栈并续接至RPN末尾
                                        int pOpnd2 = opnd.pop(),pOpnd1 = opnd.pop();//取出后、前操作数
                                        opnd.push(calcu(pOpnd1,optr2rank(op),pOpnd2));
                                        break;
                                }
                                default:printf("语法错误1\n");exit(-1);//逢语法错误,不做处理直接退出
                        }
                }
        }
        return opnd.pop();//弹出并返回最后的计算结果
}

int main()
{

        char expression;
        char RPN;
        cout << "请输入要计算的式子:";
        gets(expression);
        expression = '\0';
        cout << "计算结果为:" << evaluate(expression,RPN) << endl;
        cout << "逆波兰表达式为:" << *RPN << endl;
       
        return 0;
}

//vector_char.cpp

#include "vector_char.h"
#include <iostream>

using namespace std;

Vector_char::Vector_char()
{
        _size = 4;
        _capacity = 4;
        elem = new OperType;//建立容量为_size的数组
}

void Vector_char::expand()//空间不足时扩容
{
        if(_size < _capacity)//尚未满员时,不必扩容
                return;       
        OperType * oldElem = elem;
        elem = new OperType;//容量加倍
        for(int i= 0;i < _size;i++)
                elem = oldElem;//复制原向量内容
        delete []oldElem;//释放原空间
        cout << "该向量扩容后容量为:" << _capacity << endl;
//        print();
}

void Vector_char::shrink()//缩容
{
        if(_size << 2 > _capacity)//以25%为界
        {
                cout << "不需要缩容" << endl;
                return;
        }
        cout << "缩容后:";
//        print();
        OperType * oldElem = elem;
        elem = new OperType;//容量减半
        for(int i= 0;i < _size;i++)
                elem = oldElem;//复制原向量内容
        cout << "缩容后有" << _size << "个单位" << endl;
        delete [] oldElem;//释放原空间

}

Rank Vector_char::insert(Rank r,OperType optr)//插入
{
//        expand();//如果有必要,扩容
        for(int i = _size;i>r;i--)
                elem = elem;//自后向前,后继元素顺次后移一个单位
        elem=optr;
        _size++;//置入新元素并更新容量
//        cout << "插入e后:";
//        print();
        return r;//返回秩
}

int Vector_char::remove(Rank r)//删除秩为r的元素
{
        int e = elem;//备份被删除的元素
        remove(r,r+1);//调用区间删除算法,等效于对区间[r,r+1)的删除
        return e;//返回被删除元素
}

void Vector_char::remove(Rank lo,Rank hi)//删除区间
{
        while(hi < _size)
                elem = elem;//[hi,_size)顺次前移hi-lo个单元
        _size = lo;//更新规模,丢弃尾部[lo,_size = hi)区间
//        cout << "删除后:";
//        print();
        shrink();//若有必要,缩容
       
//        return hi - lo;//返回被删除元素的数目
}

void Vector_char::print()
{
        for(int i =0;i<_size;i++)
                cout << elem << "\t";
        cout << endl;
}

OperType * Vector_char::back(int r)//返回elem指针
{
        return elem+r;
}

bool Vector_char::empty()//判断栈内是否为空
{
        int elem_length = sizeof(elem)/sizeof(*elem);
        if (elem_length == 0)
                return true;
        else
                return false;
}

//vector_data.cpp

#include "vector_data.h"
#include <iostream>

using namespace std;

Vector_data::Vector_data()
{
        _capacity = 4;
        elem = new DataType;//建立容量为_capacity的数组
        _size = 4;
}

void Vector_data::expand()//空间不足时扩容
{
        if(_size < _capacity)//尚未满员时,不必扩容
                return;       
        DataType * oldElem = elem;
        elem = new DataType;//容量加倍
        for(int i= 0;i < _size;i++)
                elem = oldElem;//复制原向量内容
        delete []oldElem;//释放原空间
//        cout << "该向量扩容后容量为:" << _capacity << endl;
//        print();
}

void Vector_data::shrink()//缩容
{
        if(_size << 2 > _capacity)//以25%为界
        {
                cout << "不需要缩容" << endl;
                return;
        }
//        cout << "缩容后:";
//        print();
        DataType * oldElem = elem;
        elem = new DataType;//容量减半
        for(int i= 0;i < _size;i++)
                elem = oldElem;//复制原向量内容
//        cout << "缩容后有" << _size << "个单位" << endl;
        delete [] oldElem;//释放原空间
}

Rank Vector_data::insert(Rank r,DataType opnd)//插入
{
//        expand();//如果有必要,扩容
        for(int i = _size;i>r;i--)
                elem = elem;//自后向前,后继元素顺次后移一个单位
        elem=opnd;
        _size++;//置入新元素并更新容量
//        cout << "插入e后:";
        return r;//返回秩
}

int Vector_data::remove(Rank r)//删除秩为r的元素
{
        int e = elem;//备份被删除的元素
        remove(r,r+1);//调用区间删除算法,等效于对区间[r,r+1)的删除
        return e;//返回被删除元素
}

void Vector_data::remove(Rank lo,Rank hi)//删除区间
{
        while(hi < _size)
                elem = elem;//[hi,_size)顺次前移hi-lo个单元
        _size = lo;//更新规模,丢弃尾部[lo,_size = hi)区间
//        cout << "删除后:";
//        cout << "_size是:" << _size << endl;
        shrink();//若有必要,缩容
       
//        return hi - lo;//返回被删除元素的数目
}

void Vector_data::print()
{
        for(int i =0;i<_size;i++)
                cout << elem << "\t";
        cout << endl;
}

DataType * Vector_data::back(int r)
{
        return elem+r;
}


//counter_char.h

#ifndef _COUNTER_CHAR_H_
#define _COUNTER_CHAR_H_

#include<iostream>
#include "vector_char.h"//以向量为基类,派生出栈模板类

using namespace std;

class Stack_char:public Vector_char{//将向量的 首/末端 作为 栈底/顶
public:
        void push(OperType optr){insert(size(),optr);}//入栈,常引用作参数
        OperType pop(){return remove(size()-1);}//出栈,删除末元素将末元素改为其前驱
        OperType & top(){return *(back(size())-1);}//取顶 ,引用作为返回值
};
#endif

//counter_data.h

#ifndef _COUNTER_DATA_H_
#define _COUNTER_DATA_H_

#include<iostream>
#include "vector_data.h"//以向量为基类,派生出栈模板类

using namespace std;

class Stack_data:public Vector_data{//将向量的 首/末端 作为 栈底/顶
public:
        void push(DataType opnd){insert(size(),opnd);}//入栈,常引用作参数
        DataType pop(){return remove(size()-1);}//出栈,删除末元素将末元素改为其前驱
        DataType & top(){return *(back(size())-1);}//取顶 ,引用作为返回值
};

#endif

//vector_char.h

//存放操作符

//存放数字
//存放字符
#ifndef _VECTOR_CHAR_H_
#define _VECTOR_CHAR_H_

#include<iostream>
using namespace std;

typedef int Rank;
typedef char OperType;

class Vector_char
{
private:
        char *p;//p指向数组elem,用于释放数组
        OperType *elem;
        int _capacity;//_capacity是数组容量
       
public:
        Rank _size;//_size是实际规模
        Rank size()const{return _size;}//规模
        void expand();//空间不足时扩容
        void shrink();//缩容
        Rank insert(Rank r,OperType optr);//插入
        int remove(Rank r);//删除秩为r的元素
        void remove(Rank lo,Rank hi);//删除区间
        void print();
        OperType * back(int r);//返回elem指针
        bool empty();
       
        //构造函数
        Vector_char();
};

#endif

//counter_data.h

//存放数字
#ifndef _VECTOR_DATA_H_
#define _VECTOR_DATA_H_

#include<iostream>
using namespace std;

typedef int Rank;
typedef int DataType;

class Vector_data
{
private:
        int *p;//p指向数组elem,用于释放数组
        DataType *elem;
        int _capacity;//_capacity是数组容量
       
public:
        Rank _size;//_size是实际规模
        Rank size()const{return _size;}//规模
        void expand();//空间不足时扩容
        void shrink();//缩容
        Rank insert(Rank r,DataType opnd);//插入
        int remove(Rank r);//删除秩为r的元素
        void remove(Rank lo,Rank hi);//删除区间
        void print();
        DataType * back(int r);//返回elem指针
       
        //构造函数
        Vector_data();
};

#endif

哗啦哗啦啦啦啦 发表于 2020-12-14 13:00:54

main函数改一下:
int main()
{
        char expression;
        char RPN;
        cout << "请输入要计算的式子:";
        cin.getline(expression,20);
        for(int i=0;i<4;i++)
                cout << expression;
        cout << endl;
        cout << int(expression) << endl;//我输入1+2,expression为2后面的字符
        cout << "计算结果为:" << evaluate(expression,RPN) << endl;
        cout << "逆波兰表达式为:" << *RPN << endl;
       
        return 0;
}

哗啦哗啦啦啦啦 发表于 2020-12-14 13:08:36

以下为输出:

请输入要计算的式子:1+2
1+2
0
这一轮while是if
*S是:1
这一轮while是else
*S是:+
op:0
op:43
orderBetween(optr.top(),*S):<
op:0
op:43
这一轮while是if
*S是:2
不需要缩容
这一轮while是else
*S是:
op:43
op:32
语法错误3
Press any key to continue

第三行的输出为0,说明用户输入的“1+2”的2后面是'\0'
'+'对应的ascii码为43
但是在最后一轮while循环中,却是表明2后面是空格(空格对应的ascii码为32)
就是这个地方debug了我一整天都没搞懂……求助各位,这是为什么?
页: [1]
查看完整版本: C++,用户输入的字符数组结尾在程序运行中自动变空格,而不是'\0'