C++ Primer学习随便——第20章iostream

头文件 <iostream>
一. 对终端的操作
相关头文件#include <iostream>
1. 输入istream
2. 输出ostream
3. iostream继承istream和ostream 所以它具有输入输出功能。
为了方便这个库定义了下列三个标准流对象:
1. cin  代表标准输入istream类对象一般地cin使我们能够从用户终端读入数据。
2. cout 代表标准输出ostream类对象一般地cout使我们能够向用户终端写数据。
3. cerr 代表标准错误ostream类对象一般地cerr是导出程序错误消息的地方。
另外,输出主要由重载的左移操作符<< 来完成类似地输入主要由重载的右移操作符>>来完成。
Demo1:

#include <iostream>
#include <string>
int main() {
    string in_string;
    // 向用户终端写字符串
    std::cout << "Please enter your name: ";
    // 把用户输入的读取到 in_string 中
    std::cin >> in_string;
    if ( in_string.empty() )
    // 产生一个错误消息输出到用户终端
    std::cerr << "error: input string is empty!/n";
    else std::cout << "hello, " << in_string << "!/n";
}

二. 对文件的操作
相关头#include <fstream>
1. ifstream 从istream 派生把一个文件绑到程序上从文件读取数据用来输入。
2. ofstream 从ostream 派生把一个文件绑到程序上用来向文件写入数据。
3. fstream 从iostream 派生把一个文件绑到程序上用来输入和输出。
注:由于在fstream 头文件中也包含了iostream 头文件所以我们不需要同时包含这两个文
件C++对于文件的输入输出也支持同样的输入和输出操作符。
Demo2:

#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
int main()
{
    string ifile;
    cout << "Please enter file to sort: ";
    cin >> ifile;
    // 构造一个 ifstream 输入文件对象
    ifstream infile( ifile.c_str() );
    if( ! infile ) {
        cerr << "error: unable to open input file: " << ifile << endl;
        return -1;
    }
    string ofile = ifile + ".sort";
    // 构造一个 ofstream 输出文件对象
    ofstream outfile( ofile.c_str() );
    if( !outfile ) {
      cerr << "error: unable to open output file: " << ofile << endl;
      return -2;
    }
    string buffer;
    vector<string> text;
    int cnt = 1;
    while ( infile >> buffer ) {
        text.push_back( buffer );
        cout << buffer << ( cnt++ % 8 ? " " : "/n" );
    }
    sort( text.begin(), text.end() );
    // ok: 把排序后的词打印到 outfile
    vector<string>::iterator iter = text.begin();
    for ( cnt = 1; iter != text.end(); ++iter, ++cnt )
        outfile << *iter << (cnt%8 ? " " : "/n" );
    return 0;
}

三. 对字符流操作
相关的头文件#include <sstream>
1 istringstream 从istream 派生从一个字符串中读取数据。
2 ostringstream 从ostream 派生写入到一个字符串中。
3 stringstream 从iostream 派生从字符串中读取或者写入到字符串中。
Demo3:

#include <sstream>
string program_name( "our_program" );
string version( "0.01" );
// ...
string mumble( int *array, int size )
{
    if ( ! array ) {
        ostringstream out_message;
        out_message << "error: "
        << program_name << "--" << version
        << ": " << __FILE__ << ": " << __LINE__
        <<" -- ptr is set to 0; "
        << " must address some array./n";
        // 返回底层 string 对象
        return out_message.str();
}

四. wchar_t型
支持wchar_t类型的流读写操作
wcin wcout wcerr wiostream 等等....

20.1 输出操作符<<
1. 支持所有的内置数据类型 包括string ,const char* 和complex。以及函数的调用。
2. endl等价于输出换行操作符,然后再刷新缓存区。cout << ‘/n‘ << flush;
3. <<可以连接使用,因为operator<<的返回值是ostream&。
4. cout << p << &i << endl;会输出指针的地址(p是int *,i是int)。如果是const char * pcStr不会输出指针地址值,
输出的是字符串。转换为cout << static_cast<void *>(const_cast<char *>(pcStr));
5. <<运算符的优先级高于?:所以和?:使用时注意加括号。
6. ostream_iterator和cout的使用。
Demo4:

#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
string pooh_pals[] = {
"Tigger", "Piglet", "Eeyore", "Rabbit"
};
int main()
{
    vector<string> ppals( pooh_pals, pooh_pals+4 );
    vector<string>::iterator iter = ppals.begin();
    vector<string>::iterator iter_end = ppals.end();
    cout << "These are Pooh‘s pals: ";
    // 把每个元素拷贝到 cout ...
    ostream_iterator< string > output( cout, " " );
    copy( iter, iter_end, output );
    cout << endl;
}

7. cout << 遇到‘/0’会定制输出。

20.2 输入操作符>>
1. while(cin >> 变量)的时候有两种情况会让循环停止(false):
(1) 读到文件结束在这种情况下我们已经正确地读完文件中所有的值。
(2) 遇到一个无效的值比如3.14159小数点是非法的1e-1字符文字e是非法的或者一般的任意字符串文字在读入一个无效值的
情况下istream对象被放置到一种错误的状态中并且对于值的所有读入动作都将停止。
2. 预定义的输入操作符可以接受任何的内置数据类型包括C 风格字符由以及标准库string和complex 类类型。
3. 缺省情况下输入操作符丢弃任何中间空白空格制表符换行符走纸以及回车。
Demo5:

#include <iostream>
#include <string>
int main()
{
    int item_number;
    string item_name;
    double item_price;
    cout << "Please enter the item_number, item_name, and price: " << endl;
    cin >> item_number;
    cin >> item_name;
    cin >> item_price;
    cout << "The values entered are: item# "
        << item_number << " "
        << item_name << " @$"
        << item_price << endl;
}

4. 如果希望读入空白符号可以利用cin.get()方法一个个读入,或者设置skipws和noskipws选项(后面介绍)。
5. isream_iterator和cin关联使用。
Demo6:

#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
int main()
{
    istream_iterator< string > in( cin ), eos ;
    vector< string > text ;
    // 从标准输入向 text 拷贝值
    copy( in , eos , back_inserter( text ) ) ;
    sort( text.begin() , text.end() ) ;
    // 删除所有重复的值
    vector< string >::iterator it ;
    it = unique( text.begin() , text.end() ) ;
    text.erase( it , text.end() ) ;
    // 显示结果 vector
    int line_cnt = 1 ;
    for ( vector< string >::iterator iter = text.begin();
    iter != text.end() ; ++iter , ++line_cnt )
    cout << *iter
        << ( line_cnt % 9 ? " " : "/n" ) ;
    cout << endl;
}

20.2.1 字符串输入
1. setw函数:防止读入字符串益处(char[4],输入4个以上字节),while ( cin >> setw( bufSize ) >> buf )
这里bufSize是字符数组buf的长度setw()把长度等于或大于bufSize 的字符串分成最大长度为bufSize - 1的两个
或多个字符串,在每个新串的末尾放一个空字符为了使用setw()要求程序包含iomanip头文件#include <iomanip>。
2. 用string没有char *那些长度和内存溢出问题,更容易使用。

20.3 其他输入输出操作符
一. istream的成员get()一次读入一个字节。属于istream
1. get(char& ch)从输入流中提取一个字符包括空白字符并将它存储在ch中它返回被应用的istream对象。
与之对应的是ostream的put()方法,每次读入一个字节,然后返回ostream。
2. get()的第二个版本也从输入流读入一个字符区别是它返回该字符值而不是被应用的istream 对象它的返回类型
是int 而不是char 因为它也返回文件尾的标志end-of-file该标志通常用-1 来表示以便与字符集区分开为测试返回
值是否为文件尾我们将它与iostream 头文件中定义的常量EOF 做比较。
Demo7:

#include <iostream>
int main()
{
    int ch;
    // 或使用:
    // while (( ch = cin.get() ) && ch != EOF)
    while (( ch = cin.get()) != EOF)
    cout.put(ch);
    return 0;
}

3. get(char *sink, streamsize size, char delimiter=‘/n‘)
(1) sink 代表一个字符数组用来存放被读取到的字符。
(2) size 代表可以从istream 中读入的字符的最大数目。
(3) delimiter 表示如果遇到它就结束读取字符的动作delimiter 字符本身不会被读入而是留在istream 中作为istream 的
下一个字符一种常见的错误是在执行第二个get()之前忘了去掉delimiter。

二. ignore( streamsize length = 1, int delim = traits::eof )函数: 属于istream
我们用istream 成员函数ignore()来去掉delimiter
缺省情况下换行符被用作delimiter。

三. gcount()函数: 属于istream
它返回由最后的get()或getline()调用实际提取的字符数。
Demo8:

#include <iostream>
int main()
{
    const int max_line = 1024;
    char line[ max_line ];
    while ( cin.get( line, max_line ))
    {
        // 最大读取数量 max_line - 1, 也可以为 null
        int get_count = cin.gcount();
        cout << "characters actually read: "
        << get_count << endl;
        // 处理每一行
        // 如果遇到换行符
        // 在读下一行之前去掉它
        if ( get_count & max_line-1 )
            cin.ignore();
     }
}

四. getline(char *sink, streamsize size, char delimiter=‘/n‘)属于istream

五. write( const char *sink, streamsize length )属于ostream
提供了另外一种方法可以输出字符数组”它不是输出直到终止空字符为止的所有字符“而是输出某个长度的字符序列包括内含的
空字符它的函数。length 指定要显示的字符个数write()返回当前被调用的ostream 类对象。

六. read( char* addr, streamsize size )属于istream
read()从输入流中提取size 个连续的字节并将其放在地址从addr 开始的内存中gcount()返回由最后一个read()调用提取的字
节数而read()返回当前被调用的istream 类对象。
Demo9:

#include <iostream>
int main()
{
    const lineSize = 1024;
    int lcnt = 0; // 读入多少行
    int max = -1; // 最长行的长度
    char inBuf[ lineSize ];
    // 读取 1024 个字符或者遇到换行符
    while (cin.getline( inBuf, lineSize ))
    {
         // 实际读入多少字符
         int readin = cin.gcount();
         // 统计: 行数最长行
         ++lcnt;
         if ( readin > max )
             max = readin;
         cout << "Line #" << lcnt
             << "/tChars read: " << readin << endl;
         cout.write( inBuf, readin).put(‘/n‘).put(‘/n‘);
     }
     cout << "Total lines read: " << lcnt << endl;
     cout << "Longest line read: " << max << endl;
}

七. getline( istream &is, string str, char delimiter );                         
这个getline()实例的行为如下读入最大数目为str::max_size-1 个字符如果输入序列超出这个限制则读操作失败
并且istream 对象被设置为错误状态否则当读到delimiter 它被从istream 中丢弃但没有被插入到string 中或遇
到文件结束符时输入结束。

八. putback( char c ); 将字符放回 iostream。

九. unget();往回重置下一个 istream 项。

十. peek(); 返回下一个字符或 EOF,但不要提取出来。
Demo10:

char ch, next, lookahead;
while ( cin.get( ch ))
{
    switch (ch) {
    case ‘/‘:
     // 是注释行吗? 用 peek() 看一看:
     // 是的? ignore() 余下的行
     next = cin.peek();
     if ( next == ‘/‘ )
         cin.ignore( lineSize, ‘/n‘ );
     break;
     case ‘>‘:
     // 查找 >>=
     next = cin.peek();
     if ( next == ‘>‘ ) {
         lookahead = cin.get();
         next = cin.peek();
     if ( next != ‘=‘ )
     cin.putback( lookahead );
}

20.4 重载输出操作符<<
输出操作符是一个双目操作符它返回一个ostream 引用重载定义的通用框架如下
// 重载 output 操作符的通用框架
ostream&
operator <<( ostream& os, const ClassType &object )
{
// 准备对象的特定逻辑
// 成员的实际输出
os << // ...
// 返回 ostream 对象
return os;
}
注:因为第一个实参是一个ostream 引用所以输出操作符必须定义为非成员函数,当输出操作符要求访问非公有成员
时必须将它声明为该类的友元。

20.5 重载输入操作符>>
1 由于不正确的格式而导致失败istream 应该把状态标记为fail。setstate( ios_base::failbit )。
2 对于错误状态中的iostream 插入和提取操作没有影响。
Demo11:

#include <iostream>
#include "WordCount.h"
/* 必须修改 WordCount, 指定输入操作符为友元
class WordCount {
    friend ostream& operator<<( ostream&, const WordCount& );
    friend istream& operator>>( istream&, WordCount& );
*/
istream&
operator>>( istream &is, WordCount &wd )
{
/* WordCount 对象被读入的格式:
 * <2> string
 * <7,3> <12,36>
 */
int ch;
/* 读入小于符号, 如果不存在
 * 则设置 istream 为失败状态并退出
 */
if ((ch = is.get()) != ‘<‘ )
{
    is.setstate( ios_base::failbit );
    return is;
}
 // 读入多少个
 int occurs;
 is >> occurs;
 // 取 >; 不检查错误
 while ( is && (ch = is.get()) != ‘>‘ );
 is >> wd._word;
 // 读入位置
 // 每个位置的格式: < line, col >
 for ( int ix = 0; ix < occurs; ++ix )
 {
  int line, col;
  // 提取值
  while (is && (ch = is.get())!= ‘<‘ );
  is >> line;
  while (is && (ch = is.get())!= ‘,‘ );
  is >> col;
  while (is && (ch = is.get())!= ‘>‘ );
  wd.occurList.push_back( Location( line, col ));
 }
 return is;
}

20.6 文件输入和输出
包含头文件#include <fstream>
1. ofstream的构造函数要制定打开模式
输出模式ios_base::out 或附加模式ios_base::app 等等。在缺省情况下ostream文件以输出模式打开。
注:如果在输出模式下打开已经存在的文件则所有存储在该文件中的数据都将被丢弃如果我们希望增加而不是替换现
有文件中的数据则应该以附加模式打开文件于是新写到文件中的数据将添加到文件尾部在这两种模式下如果文件不存
在程序都会创建一个新文件。
2. 判断是否打开if (!outFile /*ofstream对象*/)
3. 因为ofstream派生于ostream,所以ofstream拥有ostream的操作,比如put()等等。
4. 自定义<<操作输入到ofstream中。
5. 用ifstream读入一个文件,派生于istream,所有拥有istream的操作,比如get()等等。
6. close()函数断开和文件的关联。
7. fstream派生于iostream,它具有对文件的读写操作。
8. seekg和seekp标记当前位置,g是在读文件中使用,p再写文件中使用。
注:第二个参数标示定位标记:
(1) ios_base::beg 文件的开始
(2) ios_base::cur 文件的当前位置
(3) ios_base::end 文件的结尾
9. tellg()或tellp()返回当前位置,g和p意义同seekg和seekp。返回值是ios_base::pos_type。
10. clear()函数:清除状态。

20.7 条件状态
一. 条件状态
1 如果一个流遇到文件结束符则eof()返回true。
2 如果试图做一个无效的操作比如seeking 重定位操作超出了文件尾则bad()返回true,一般地这表示该流由于某种
未定义的方式而被破坏了。
3 如果操作不成功比如打开一个文件流对象失败或遇到一种无效的输入格式则fail()
返回true 例如
ifstream iFile( filename, ios_base::in );
if ( iFile.fail() ) // 不能打开
error_message( ... );
4 如果其他条件都不为true 则good()返回true

二. 改变状态
1. clear()函数,状态变为显示。
2. setstate()函数,添加状态。参数设置为:
ios_base::badbit
ios_base::eofbit
ios_base::failbit
ios_base::goodbit
3. rdstate()获取成员状态,返回值ios_base::iostate。

20.8 string 流
1. 包括头文件#include <sstream>
2. str()返回与ostringstream 类对象相关联的string 对象。

20.9 格式状态
操 作 符                    含 义
boolalpha               把true 和false 表示为字符串
*noboolalpha            把true 和false 表示为0 1
showbase                产生前缀指示数值的进制基数
*noshowbase             不产生进制基数前缀
showpoint               总是显示小数点
*noshowpoint            只有当小数部分存在时才显示小数点
Showpos                 在非负数值中显示+
*noshowpos              在非负数值中不显示+
*skipws                 输入操作符跳过空白字符
noskipws                输入操作符不跳过空白字符
uppercase               在十六进制下显示0X 科学计数法中显示E
*nouppercase            在十六进制下显示0x 科学计数法中显示e
*dec                    以十进制显示
hex                     以十六进制显示
oct                     以八进制显示
left                    将填充字符加到数值的右边
right                   将填充字符加到数值的左边
Internal                将填充字符加到符号和数值的中间
*fixed                  以小数形式显示浮点数
scientific              以科学计数法形式显示浮点数
flush                   刷新ostream 缓冲区
ends                    插入空字符然后刷新ostream 缓冲区
endl                    插入换行符然后刷新ostream 缓冲区
ws                      吃掉 空白字符
// 以下这些要求 #include <iomanip>
setfill(ch)            用ch 填充空白字符
setprecision(n)        将浮点精度设置为n
setw(w)                按照w 个字符来读或者写数值
setbase(b)             以进制基数b 输出整数值
注*表示缺省的流状态

20.10 强类型库
iostream库是强类型的例如试图从一个ostream 读数据或者写数据到一个istream都会在编译时刻被捕获到并标记为类型违例

时间: 2024-10-10 06:18:32

C++ Primer学习随便——第20章iostream的相关文章

C++ Primer学习总结 第6章 函数

第6章 函数 1.    函数最外层作用域中的局部变量不能使用与函数形参一样的名字,因为它们属于同一个作用域范围. 2.    局部静态变量的生命周期: 在整个程序的执行路径第一次经过对象定义语句时初始化,并且直到整个程序终止时才被销毁,在此期间即使对象所在函数结束执行也不会对它有影响. 3.    如果重载的函数的参数只有顶层const区别,那么是错误的: 如果有底层const区别可以算作重载. 4.    如果函数的参数要使用引用(且不会改变引用对象的值),那么应该定义成常量引用. 因为使用

C++ Primer学习总结 第7章 类

第7章 类 1.    引入const成员函数(C++ Primer P231-232) C++类的常量对象是无法调用非const成员函数的,如果想让常量对象调用某个成员函数,必须声明成const: 2.     一个类的尾后const成员函数如果返回*this,那么其返回类型必然是const 类名 & 前面这个const是不能少的.否则无法通过编译. 3.    默认构造函数P235-236 编译器只有在发现类中不包含任何构造函数的情况下,才会为我们合成一个默认的构造函数,且该函数对于类中的成

C++ Primer学习总结 第8章 IO库

 第8章 IO库 1.    IO类继承关系: 2.    查询iostream流状态P280-281 V是一个int,当我们输入1, 'r',或Ctrl+z 时的输出分别如下: cin.clear()可以清楚所有的错误位,使good()返回true. 3.    fstream对文件的读写P284 初始创建读入和写出fstream对象之后,把fin和fout完全看成cin和cout处理即可,它们操作几乎没有区别. 4.    对同一个文件同时打开进行读写会出现不可预知的BUG. 对于文件的操作

C++ Primer学习总结 第10章 泛型算法

第10章 泛型算法 1.    find()泛型算法使用示例: 2.    只读算法accumulate:对所给范围的元素求和并返回. 注意accumulate的第3个参数决定着它的返回类型. 即如果第3个参数是double,就算迭代器里都是int,最终还是返回double类型的数. 3.    只读算法equal:比较前两个迭代器表示范围的所有元素是否与第3个迭代器表示的对应位置的元素都相同,如果相同返回true.两个容器类型可以不同,保存的元素类型也可以不同,只要元素之间可以比较即可.如st

C++ Primer学习总结 第13章 拷贝控制

第13章 拷贝控制 1.    什么是拷贝构造函数? P440 如果一个类的构造函数的第一个参数是自己类类型的引用, 且所有其他参数都有默认值, 那么这就是一个拷贝构造函数. 2.    拷贝初始化和直接初始化.  P441 如果初始化的时候使用等号"="来初始化一个对象, 那么就是拷贝初始化. 相反, 如果初始化时, 没有用等号"=", 那么就是直接初始化. 如果是拷贝初始化, 那么用的一定是拷贝构造函数(也有可能用移动构造函数). 如果是直接初始化, 那么就用参

C++ Primer学习总结 第5章 语句

第5章 语句 1.    switch中的case标签必须是整型常量表达式,不能是变量也不能是非整型: 注意第二个case 3.14 在C++11中没错误可以执行,但是在C++98中编译不通过. 2.    switch语句的case语句初始化了一个变量时要注意: Case语句不能跳过变量的初始化,可以跳过变量的定义. 3.    范围for语句不仅仅能用auto声明变量: 不过对于数组,使用范围for语句要小心   4.    goto语句不能跳过变量的初始化,可以跳过变量的定义: 5.   

C++ Primer学习总结 第4章 表达式

 第4章 表达式 1.    decltype作用于左值对象时,返回的是该对象的引用类型. 作用于右值对象时,返回的是该对象的类型. 2.    求值顺序. C++中只有&& || ?: 和, 4种运算符是先左后右求值的. 3.    一元正负号运算符作用于数值: 会提升当前数值的类型,比如short变成int型   4.    m%(-n) 与 (-m)%n 与 (-m)%(-n) 的结果分别是: 注意: 模的正负号没有任何影响, m的正负号决定结果的正负.   5.     关系运算符

C++ Primer学习总结 第1-2章 变量和基本类型

第1-2章 变量和基本类型 1.下面这个语句在C++98和C++11中的输出结果不同. C++98结果: (如果想要更高的精度,可以用%.9lf,输出9位有效数字) C++11结果: 结论: printf的%lf在C++11中表示longdouble,所以用中%f就可以输出float和double类型.而printf在C++98中可以用%lf正确输出double. 如果是scanf的话,不论C++98还是C++11中float都用%f读取,double都用%lf读取,因为二者结构不同.   2.

C++ Primer学习总结 第3章 字符串,向量和数组

第3章 字符串,向量和数组 1.    如何用string读取一整行内容? 用getline(cin,s)即可. 当然getline()也可以用来作为while循环读取输入的判断条件. 2.    string与字符串字面值,字符字面值相加 由于+法是从左向右运算的,所以只要保证每次两个值相加时,+号左右两边至少有一个是string就行. 3.    string不仅可以与字符串字面值相加,还可以与以'\0'字符结束的字符串数组相加. 4.    注意下面数组的初值: 如果a与b数组都是全局的话