C++之IO类,文件输入输出,string流练习题

编辑: admin 分类: c#语言 发布时间: 2021-12-12 来源:互联网
目录
  • 前面已经在用的IO库设施
  • IO类
  • IO对象不能拷贝或赋值
    • 条件状态
    • 管理输出缓冲
  • 文件输入输出
    • fstream特有的操作
    • 文件模式
  • string流
    • stringstream特有的操作
  • 练习
    • 练习1
    • 练习2
    • 练习3
    • 练习4
    • 练习5
    • 练习6
    • 练习7
    • 练习8
    • 练习9
  • 总结

    前面已经在用的IO库设施

    • istream:输入流类型,提供输入操作。
    • ostream:输出流类型,提供输出操作
    • cin:一个istream对象,从标准输入读取数据。
    • cout:一个ostream对象,向标准输出写入数据。
    • cerr:一个ostream对象,向标准错误写入消息。
    • >>运算符:用来从一个istream对象中读取输入数据。
    • <<运算符:用来向一个ostream对象中写入输出数据。
    • getline函数:从一个给定的istream对象中读取一行数据,存入到一个给定的string对象中。

    IO类

    • iostream头文件:从标准流中读写数据,istream,ostream
    • fstream头文件:从文件中读写数据,ifstream,ofstream
    • sstream头文件:从字符串中读写数据,istringstream,ostringstream

    IO对象不能拷贝或赋值

    由于不能拷贝IO对象,因此不能将 形参 或 返回类型 设置为 流类型。进行 IO 操作的函数通常以 引用方式 传递和 返回流。读写一个IO对象会改变其状态,因此 传递和返回的引用不能用const。

    • IO对象不能存在容器里.
    • 形参和返回类型也不能是流类型。
    • 形参和返回类型一般是流的引用。
    • 读写一个IO对象会改变其状态,因此传递和返回的引用不能是const的。

    条件状态

    状态 解释 strm:iostate 是一种机器无关的类型,提供了表达条件状态的完整功能 strm:badbit 用来指出流已经崩溃 strm:failbit 用来指出一个IO操作失败了 strm:eofbit 用来指出流到达了文件结束 strm:goodbit 用来指出流未处于错误状态,此值保证为零 s.eof() 若流s的eofbit置位,则返回true s.fail() 若流s的failbit置位,则返回true s.bad() 若流s的badbit置位,则返回true s.good() 若流s处于有效状态,则返回true s.clear() 将流s中所有条件状态位复位,将流的状态设置成有效,返回void s.clear(flags) 将流s中指定的条件状态位复位,返回void s.setstate(flags) 根据给定的标志位,将流s中对应的条件状态位置位,返回void s.rdstate() 返回流s的当前条件状态,返回值类型为strm::iostate

    上表中,strm是一种IO类型,(如istream), s是一个流对象。

    管理输出缓冲

    • 每个输出流都管理一个缓冲区,用来保存程序读写的数据。文本串可能立即打印出来,也可能被操作系统保存在缓冲区内,随后再打印。
    • 刷新(即,数据真正写到输出设备或文件)缓冲区的IO操纵符
      • endl:输出一个换行符并刷新缓冲区
      • flush:刷新流,但不添加任何字符
      • ends:在缓冲区插入空字符null,然后刷新
      • unitbuf:告诉流接下来每次操作之后都要进行一次flush操作。
      • nounitbuf:回到正常的缓冲方式

    文件输入输出

    头文件fstream定义了三个类型来支持文件IO:

    • ifstream从一个给定文件读取数据。
    • ofstream向一个给定文件写入数据。
    • fstream可以读写给定文件。

    fstream特有的操作

    操作 解释 fstream fstrm; 创建一个未绑定的文件流。 fstream fstrm(s); 创建一个文件流,并打开名为s的文件,s可以是string也可以是char指针 fstream fstrm(s, mode); 与前一个构造函数类似,但按指定mode打开文件 fstrm.open(s) 打开名为s的文件,并和fstrm绑定 fstrm.close() 关闭和fstrm绑定的文件 fstrm.is_open() 返回一个bool值,指出与fstrm关联的文件是否成功打开且尚未关闭

    上表中,fstream是头文件fstream中定义的一个类型,fstrm是一个文件流对象。

    文件模式

    文件模式 解释 in 以读的方式打开 out 以写的方式打开 app 每次写操作前均定位到文件末尾 ate 打开文件后立即定位到文件末尾 trunc 截断文件 binary 以二进制方式进行IO操作。

    string流

    头文件sstream定义了三个类型来支持内存IO:

    • istringstream从string读取数据。
    • ostringstream向string写入数据。
    • stringstream可以读写给定string。

    stringstream特有的操作

    操作 解释 sstream strm 定义一个未绑定的stringstream对象 sstream strm(s) 用s初始化对象 strm.str() 返回strm所保存的string的拷贝 strm.str(s) 将s拷贝到strm中,返回void

    上表中sstream是头文件sstream中任意一个类型。s是一个string。

    书中演示demo使用

    #include <iostream>
    #include <string>
    #include <vector>
    #include <sstream>
    using namespace std;
    typedef struct PersonInfo
    {
    	string name;
    	vector<string> phones;
    }p;
    int main() {
    	string line, word;
    	vector<p> people;
    	while (getline(cin, line))
    	{
    		p info;
    		istringstream record(line);
    		record >> info.name;
    		while (record >> word)
    			info.phones.push_back(word);
    		people.push_back(info);
    	}
    
    	for (auto i : people)
    	{
    		cout << i.name << endl;
    		for (auto j : i.phones)
    			cout << j << "   ";
    		cout << endl;
    	}
    	return 0;
    }
    

    练习

    练习1

    编写函数,接受一个istream&参数,返回值类型也是istream&。此函数须从给定流中读取数据,直至遇到文件结束标识时停止。它将读取的数据打印在标准输出上。完成这些操作后,在返回流之前,对流进行复位,使其处于有效状态。

    解:

    std::istream& func(std::istream &is)
    {
        std::string buf;
        while (is >> buf)
            std::cout << buf << std::endl;
        is.clear();
        return is;
    }
    

    练习2

    测试函数,调用参数为cin。

    解:

    #include <iostream>
    using std::istream;
    istream& func(istream &is)
    {
        std::string buf;
        while (is >> buf)
            std::cout << buf << std::endl;
        is.clear();
        return is;
    }
    int main()
    {
        istream& is = func(std::cin);
        std::cout << is.rdstate() << std::endl;
        return 0;
    }
    

    测试

    #include <iostream>
    #include <string>
    using namespace std;
    istream& f1(istream& is)
    {
    	int s;
    	while (is >> s)
    	{
    		cout << s << endl;
    	}
    	return is;
    }
    istream& f2(istream& is)
    {
    	int s;
    	while (is >> s)
    	{
    		cout << s << endl;
    	}
    	is.clear();
    	return is;
    }
    int main()
    {
    	istream& is = f1(cin);
    	cout << is.rdstate() << endl;
    	istream& is2 = f2(cin);
    	cout << is2.rdstate() << endl;
    	return 0;
    }
    

    练习3

    什么情况下,下面的while循环会终止?

    while (cin >> i) /*  ...    */
    

    如badbit、failbit、eofbit 的任一个被置位,那么检测流状态的条件会失败。

    练习4

    编写函数,以读模式打开一个文件,将其内容读入到一个string的vector中,将每一行作为一个独立的元素存于vector中。

    #include <iostream>
    #include <string>
    #include <vector>
    #include <fstream>
    using namespace std;
    void ReadFileToVec(const string& filename, vector<string>& vec)
    {
    	ifstream ifs(filename);
    	if (ifs)
    	{
    		string buf;
    		while (getline(ifs, buf))
    			vec.push_back(buf);
    	}
    }
    

    练习5

    重写上面的程序,将每个单词作为一个独立的元素进行存储。

    void ReadFileToVec(const string& fileName, vector<string>& vec)
    {
        ifstream ifs(fileName);
        if (ifs)
        {
            string buf;
            while (ifs >> buf)
                vec.push_back(buf);
        }
    }
    

    练习6

    编写程序,将来自一个文件中的行保存在一个vector中。然后使用一个istringstream从vector读取数据元素,每次读取一个单词。

    #include <iostream>
    #include <string>
    #include <sstream>
    #include <fstream>
    #include <vector>
    using namespace std;
    int main()
    {
    	//将来自一个文件的行保存到vector中
    	ifstream ifs("hello.txt");
    	if (!ifs)
    	{
    		cerr << "no data ?" << endl;
    		return -1;
    	}
    	vector<string> vecline;
    	string line;
    	while(getline(ifs, line))
    		vecline.push_back(line);
    	ifs.close();
    	//从vector读取元素,每次只读一个单词
    	for (auto &s : vecline)
    	{
    		istringstream iss(s);
    		string word;
    		while (iss >> word)
    			cout << word << endl;
    	}
    	return 0;
    }
    

    练习7

    本节的程序在外层while循环中定义了istringstream对象。如果record对象定义在循环之外,你需要对程序进行怎样的修改?重写程序,将record的定义移到while循环之外,验证你设想的修改方法是否正确。

    解:

    #include <iostream>
    #include <sstream>
    #include <string>
    #include <vector>
    using std::vector; using std::string; using std::cin; using std::istringstream;
    struct PersonInfo {
        string name;
        vector<string> phones;
    };
    int main()
    {
        string line, word;
        vector<PersonInfo> people;
        istringstream record;
        while (getline(cin, line))
        {
            PersonInfo info;
            record.clear();
            record.str(line);
            record >> info.name;
            while (record >> word)
                info.phones.push_back(word);
            people.push_back(info);
        }
        for (auto &p : people)
        {
            std::cout << p.name << " ";
            for (auto &s : p.phones)
                std::cout << s << " ";
            std::cout << std::endl;
        }
        return 0;
    }
    

    练习8

    我们为什么没有在PersonInfo中使用类内初始化?

    解:

    因为这里只需要聚合类就够了,所以没有必要在PersionInfo中使用类内初始化。

    练习9

    电话号码程序

    #include <iostream>
    #include <string>
    #include <sstream>
    #include <fstream>
    #include <vector>
    using namespace std;
    struct PersonInfo {
    	string name;
    	vector<string> phones;
    };
    bool valid(const string& str)
    {
    	return isdigit(str[0]);
    }
    string format(const string& str)
    {
    	return str.substr(0, 3) + "-" + str.substr(3, 3) + "-" + str.substr(6);
    }
    int main()
    {
    	//从文件中读取信息存入vector容器
    	ifstream ifs("phone.txt");
    	if (!ifs)
    	{
    		cerr << "no phone numbers ? " << endl;
    		return -1;
    	}
    	vector<PersonInfo> people;
    	string line, word;
    	istringstream record;
    	while (getline(ifs, line))
    	{
    		PersonInfo info;
    		record.clear();
    		record.str(line);
    		record >> info.name;
    		while (record >> word)
    		{
    			info.phones.push_back(word);
    		}
    		people.push_back(info);
    	}
    	//逐个验证电话号码 并 改变其格式
    	for (const auto& entry : people)   //对people中的每一项
    	{
    		//每个循环创建的对象
    		ostringstream formatted, badnums;
    		//对每个数
    		for (const auto& nums : entry.phones)
    		{
    			if (!valid(nums))
    			{
    				badnums << " " << nums;
    				//将数的字符串形式存入badnums
    			}
    			else
    			{
    				//将格式化的字符串写入formatted
    				formatted << " " << format(nums);
    			}
    		}
    		//没有错误的数
    		if (badnums.str().empty())
    		{
    			cout << entry.name << " "
    				<< formatted.str() << endl;
    		}
    		else
    		{
    			//打印名字和错误的数
    			cerr << "input error: " << entry.name
    				<< " invalid number(s)" << badnums.str() << endl;
    		}
    	}
    	return 0;
    }
    

    总结

    本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注海外IDC网的更多内容!

    【本文由:http://www.1234xp.com/cdn.html 提供,感谢支持】