第五次作业(计算器第三步之文件输入输出)

题目要求:

http://www.cnblogs.com/fzuoop/p/5451293.html

下面按照解决的过程一一记录说明

1.文件输入输出

这个东西在谭浩强的书上也有,所以我看了点书之后先开始了粗糙的尝试,代码如下:

#include<fstream>
#include<iostream>
#include<string>
using namespace std;
int main()
{
    string str;
    //定义输入文件流对象,以输入方式打开磁盘文件text.txt
    ifstream infile("D:	ext.txt",ios::in);
    //打开失败的报错
    if(!infile)
    {
        cerr<<"open error!"<<endl;
        exit(1);
    }
    //从输入文件中获取数据,并输到屏幕上
    while(getline(infile,str,'
'))
    {
        getline(infile,str,'
');
        cout<<str<<endl;
    }
    //将输入文件流所关联的磁盘文件关闭
    infile.close();
    return 0;
}

但是运行结果一直是打开失败,百度了一下之后,把路径名中的斜杠换成了双写,然后运行结果是:


但是我的数据是:

又去百度了解之后,把输出的代码改成了这样:

while(!infile.eof())
{
	getline(infile,str,'
');
	cout<<str<<endl;
}

然后输出的结果终于对了:


然后我又定义了一个string类型来接收输入的路径名,但是编译就过不去,是在别人的博客里看到了c_str()函数(通过string类的c_str()函数能够把string对象转换成c中的字符串的样式),然后就可以了。下面是尝试的最后代码:

#include<fstream>
#include<iostream>
#include<string>
using namespace std;
int main()
{
    string str,ifile,ofile;
    //输入输入文件路径和输出文件路径
    cin>>ifile>>ofile;
    //定义输入文件流对象,以输入方式打开磁盘文件ifile
    ifstream infile(ifile.c_str(),ios::in);
    //打开失败的报错
    if(!infile)
    {
        cerr<<" infile open error!"<<endl;
        exit(1);
    }
    //定义输出文件流对象,以输入方式打开磁盘文件ofile
    ofstream outfile(ofile.c_str(),ios::out);
    //打开失败的报错
    if(!outfile)
    {
        cerr<<"outfile open error!"<<endl;
        exit(1);
    }
    //从输入文件中获取数据,传到输出文件里并输到屏幕上
    while(!infile.eof())
    {
        getline(infile,str,'
');
        outfile<<str<<endl;
        cout<<str<<endl;
    }
    //将输入文件流所关联的磁盘文件关闭
    infile.close();
    //将输出文件流所关联的磁盘文件关闭
    outfile.close();
    return 0;
}

运行结果:

输出文件结果:

2.代码修改

1.现在的表达式包括等号,于是在Scan类里做了修改,不会把最后一个等号输进去,这样子其他的按照原来的就好,具体代码如下:

Scan.cpp

#include"Scan.h"
#include<stdlib.h>
#include<iostream>
#include<string>
#include<queue>
using namespace std;
queue<string> ToStringQueue(string input)
{
    //第二次题目要求数位不超过十位(包括小数位)
    //这是用来记录数位的变量
    int cnt=0;
    queue<string>q;
    string str;
    //遍历传进来的字符串
    for(int i=0; i<input.size(); i++)
    {
        //遍历到运算符或是符号
        //注:多了一个等号的判断
        if(input[i] == '+'||input[i] == '-'||input[i] == '*'||input[i] == '/'||input[i] == '('||input[i] == ')'||input[i] =='=')
        {
            //把碰到运算符之前接起来的数字符压入队列中
            if(!str.empty())
            {
                q.push(str);
            }
            //特判第一个数字是负数的情况
            //不入栈,准备与数字符接在一起
            if(input[i]=='-'&&i==0)
            {
                str=str+input[i];
            }
            //算式中间出现合法的负数的情况
            //不入栈,准备与数字符·接在一起
            else if(input[i]=='-'&&q.back()=="(")
            {
                str=str+input[i];
            }
            //其他运算符直接入栈,并把中间变量置空
            //注:不存入等号
            else if(input[i]!='=')
            {
                cnt=0;
                str=input[i];
                q.push(str);
                str.clear();
            }
            //注:等号不做处理
            else
            {
                break;
            }    
        }
        //遍历到数字符
        else
        {
            //把相邻数字符接起来
            str=str+input[i];
            //记录位数
            if(input[i]!='.')
            {
                cnt++;
            }
            //位数报错
            if(cnt==11)
            {
                cout<<"wrong input"<<endl;
                system("pause");
            }
            //最后是数字符的话,直接入栈
            //原来都是碰到运算符才入栈
            if(i==input.size()-1)
            {
                q.push(str);
            }
        }
    }
    return q;
}

2.主要是多了一个文件输入输出的情况,然后把主函数改成了这样,然后Calculation类的成员函数也改成有返回值的:

Main.cpp

#include<stdlib.h>
#include<iostream>
#include<fstream>
#include<string>
#include<string.h>
#include<queue>
#include"Scan.h"
#include"Print.h"
#include"Calculation.h"
using namespace std;
int main(int argc, char* argv[])
{
    Scan scan;
    Print print;
    Calculation calculation;
    string input;
    double result;
    queue<string>q;
    //x为“-a”,y为表达式,则在屏幕输出表达式
    if(strcmp(argv[1],"-a")==0)
    {
        input=argv[argc-1];
        cout<<input<<" ";
    }
    //x为“-f”,y为输入文件路径,z为输出文件路径
    if(strcmp(argv[1],"-f")==0)
    {
        string ifile=argv[2];
        string ofile=argv[3];
        //定义输入文件流对象,以输入方式打开磁盘文件ifile
        ifstream infile(ifile.c_str(),ios::in);
        //打开失败的报错
        if(!infile)
        {
            cerr<<" infile open error!"<<endl;
            exit(1);
        }
        //定义输出文件流对象,以输出方式打开磁盘文件ofile
        ofstream outfile(ofile.c_str(),ios::out);
        //打开失败的报错
        if(!outfile)
        {
            cerr<<"outfile open error!"<<endl;
            exit(1);
        }
        //从输入文件里获取input的值,并把计算结果传到输出文件
        while(!infile.eof())
        {
            getline(infile,input,'
');
            q=scan.ToStringQueue(input);
            result=calculation.getStringQueue(q);
            outfile<<input<<" "<<result<<endl;
        }
        //将输入文件流所关联的磁盘文件关闭
        infile.close();
        //将输出文件流所关联的磁盘文件关闭
        outfile.close();
    }
    //x不为“-f”时在屏幕输出
    else
    {
        q=scan.ToStringQueue(input);
        result=calculation.getStringQueue(q);
        cout<<result<<endl;
    }
    system("pause");
    return 0;
}

不知道为什么会停止运行。。。不过检查输出的文件里面是确实有正确的输出的:


后来发现好像只要输出结果就好,不用把表达式也输到文件里面。。。

3.把所有关于输出的代码都放到Print类里。当初看到题目的时候就觉得这个最麻烦了,这个不做的话,感觉后面的框架图也没办法做,然后貌似代码要改很多。。。
这大概就是最终代码了:

Main.cpp

#include<stdlib.h>
#include<iostream>
#include<fstream>
#include<string>
#include<string.h>
#include<queue>
#include"Scan.h"
#include"Print.h"
#include"Calculation.h"
using namespace std;
int main(int argc, char* argv[])
{
    Scan scan;
    Print print;
    Calculation calculation;
    string input;
    double result;
    queue<string>q;
    //要求输出表达式的操作
    if(strcmp(argv[1],"-a")==0)
    {
        //从命令行读入表达式
        input=argv[argc-1];
        //调用Scan类,获得一个存表达式的队列
        q=scan.ToStringQueue(input);
        //调用Calculation类,获得计算结果
        result=calculation.getStringQueue(q);
        //调用Print类,按照要求输出
        print.putout(result,input,"0");
    }
    //要求从命令行获得输入文件和输出文件路径的操作
    else if(strcmp(argv[1],"-f")==0)
    {
        //获取命令行的输入文件路径
        string ifile=argv[2];
        //定义输入文件流对象,以输入方式打开输入文件
        ifstream infile(ifile.c_str(),ios::in);
        //打开错误的报错
        if(!infile)
        {
            cerr<<" infile open error!"<<endl;
            exit(1);
        }
        //一直读到输入文件末尾
        while(!infile.eof())
        {
            //从输入文件获取表达式
            getline(infile,input,'
');
            //调用Scan类,获得一个存表达式的队列
            q=scan.ToStringQueue(input);
            //调用Calculation类,获得计算结果
            result=calculation.getStringQueue(q);
            //调用Print类,按照要求输出
            print.putout(result,input,argv[3]);
        }
        //将输入文件流所关联的磁盘文件关闭
        infile.close();
    }
    //只要求简单输出结果的操作
    else
    {
        //从命令行读入表达式
        input=argv[argc-1];
        //调用Scan类,获得一个存表达式的队列
        q=scan.ToStringQueue(input);
        //调用Calculation类,获得计算结果
        result=calculation.getStringQueue(q);
        //调用Print类,按照要求输出
        print.putout(result,"0","0");
    }
    system("pause");
    return 0;
}

Print.cpp

#include"Print.h"
#include<stdlib.h>
#include<iostream>
#include<fstream>
#include<string>
#include<queue>
using namespace std;
void Print::putout(double res,string in,string out)
{
    //定义输出文件流对象,以输出方式打开输出文件
    string ofile=out;
    //只是简单输出结果的操作
    if(in=="0")
    {
        cout<<res<<endl;
    }
    //输出到输出文件的操作
    else if(out!="0")
    {
        //定义输出文件流对象,以输出方式打开磁盘文件ofile
        ofstream outfile(ofile.c_str(),ios::app);
        //打开错误的报错
        if(!outfile)
        {
            cerr<<"outfile open error!"<<endl;
            exit(1);
        }
        //将结果输到输出文件里
        outfile<<res<<endl;  
        //将输出文件流所关联的磁盘文件关闭      
        outfile.close();	
    } 
    //要求输出表达式和结果的操作
    else
    {
        cout<<in<<" "<<res<<endl;
    }   
} 

x是“-f”时还是会迷之崩溃,但是输出文件里确实有正确的输出。还有一件事是把输出文件的打开方式改成了ios::app,写入的数据接在原文件末尾(但是多输几次的话会重复感觉也不好),而ios::out的话会把原数据清空,我上面的代码最后会只有一个输出 。直接上GITHUB链接

3.框架图

其实不懂框架图是什么意思,大概做了一下:

ps:感觉又是一次要改很久的作业。。。

原文地址:https://www.cnblogs.com/mingyueanyao/p/5474814.html