【C++ 程序设计】第 7 章:输入/输出流

目录

一、流类简介

二、标准流对象 

三、控制I/O格式 

(1)流操纵符 

(2)标志字

四、调用cout的成员函数【示例一】

五、调用 cin 的成员函数 

(1)get() 函数 

(2)getline() 函数

(3)eof() 函数 

(4)ignore() 函数 

(5)peek() 函数 




一、流类简介

  • C++ 中凡是数据从一个地方传输到另一个地方的操作都是的操作。
  • 因此,一般意义下的读操作在流数据抽象中被称为(从流中)“提取” ,写操作被称为(向流中)“插入” 。
  • 在 C++ 中,输入输出的完成是通过

  • 图中的箭头代表派生关系。
  • ios 是抽象基类,提供输入/输出所需的公共操作,它派生出两个类 istream 和 ostream。
  • 为了避免多重继承的二义性,从 ios 派生 istream 和 ostream 时,均使用了 virtual 关键字(虚继承)
  • istream 类提供了流的大部分输入操作,对系统预定义的所有输入流重载提取运算符 “>>”。
  • ostream 类对系统预定义的所有输出流重载插入运算符 “<<”。
  • 由 istream 和 ostream 又共同派生了 iostream 类。
C++ 的 iostream 类库提供了数百种 I/O 功能,iostream 类库的接口部分包含在几个头文件中。
常见的头文件有以下 3 个:

① iostream

  • 头文件 iostream 包含操作所有输入/输出流所需的基本信息,因此大多数 C++ 程序都 应包含这个头文件。
  • 该文件含有4个标准流对象,提供了无格式化和格式化的I/O功能。
 iomanip
  • 例如:setw(),setprecision(),setfill(),setbase() 等。
  • 头文件 iomanip 包含格式化 I/O 的带参数流操纵符,可用于指定数据输入/输出的格式。
 fstream
  • 头文件 fstream 包含处理文件的有关信息,提供建立文件、读/写文件的各种操作接口。


二、标准流对象 

C++ 在头文件 iostream 中为用户预定义了 4 个标准流对象,分别是:
  • cin (标准输入流)
  • cout (标准输出流)
  • cerr (非缓冲错误输出流)
  • clog (缓冲错误输出流)
  • cin 与标准输入设备(键盘)相关联,用于读取数据,可以被重定向为从文件中读取数据
  • cout 与标准输出设备(显示器)相关联,用于输出数据,可以被重定向为向文件里写入数据
  • cerr 与标准错误信息输出设备(显示器)相关联(非缓冲),用于输出出错信息,不能被重定向。
  • clog 与标准错误信息输出设备相关联(缓冲),用于输出出错信息,不能被重定向。
  • 在实际中,cin 常用于从键盘输入数据,是流类 istream 的对象。
  • cout 常用于向屏幕输出数据,是流类 ostream 的对象。

【示例】 将标准输出 cout 重定向到文件

【示例代码】

#include <iostream>
using namespace std;

int main() {
    int x, y;
    cin >> x >> y;

    freopen("test.txt", "w", stdout);  // 将标准输出重定向到文件 test.txt

    if (y == 0)  // 除数为 0 则输出错误信息
        cerr << "error." << endl;
    else
        cout << x << "/" << y << "=" << x / y << endl;

    return 0;
}

【代码详解】

  • 函数 freopen() 的功能是将 stream 按 mode 指定的模式重定向到路径 path 指向的文件。
  • 这段代码读入两个整数 x 和 y,然后将标准输出重定向到文件 test.txt,接着判断是否除数 y 为 0,如果是则输出错误信息,否则输出 x/y 的值并换行。这里使用了标准输出流 cout 和标准错误流 cerr,它们都是从 ostream 类派生而来的流对象。在标准情况下,cout 和 cerr 输出的内容都会直接输出到控制台窗口,但是通过重定向可以将它们输出到文件或管道。

  • 在这里,freopen() 函数将标准输出流 stdout 重定向到 test.txt 文件,这意味着后续所有通过 cout 输出的内容都会写入到 test.txt 文件里,而不会在控制台中输出。由于本代码只有一条输出语句,因此只有一行输出会写入到 test.txt 中。如果这里输出的内容比较多,可以通过重定向避免在控制台中输出过多的内容。

  • 注意,freopen() 函数可以重定向标准输入流 stdin 和标准输出流 stdout,同时也可以重定向标准错误流 stderr,这里使用了标准输出流 stdout。另外,当程序运行时,会先执行 main() 函数中的代码,然后才开始执行重定向的操作,因此输入的数据会先被读入,输出的结果会在重定向后才写入文件中。

  1. #include <iostream>,引入输入输出流相关的库。
  2. using namespace std;,使用 std 命名空间。
  3. int main() { ,程序入口。
  4. int x, y;,定义两个整型变量 x 和 y
  5. cin >> x >> y;,从控制台读取两个整数。
  6. freopen("test.txt", "w", stdout);,将标准输出重定向到文件 test.txt,后续所有的输出都会写入到该文件。
  7. if (y == 0),判断除数是否为 0。
  8. cerr << "error." << endl;,输出错误信息到标准错误流。
  9. else,当除数不为 0 时执行以下代码。
  10. cout << x << "/" << y << "=" << x / y << endl;,输出 x/y 的值。
  11. return 0;,返回程序执行结果。

【执行结果】

  • 这段代码的作用是,读入两个整数 x 和 y,如果 y 不为 0,则输出 x/y 的值,否则输出错误信息,并将输出结果写入到 test.txt 文件中。
  • 运行时需要在控制台中输入两个整数,如 4 2,然后程序会在 test.txt 文件中生成一行输出 4/2=2。如果输入的除数为 0,如 2 0,则程序会在控制台输出错误信息:error.,并不会在 test.txt 中进行任何输出。
  1. 输入 2 0,因为除数为 0,所以程序会输出一个错误信息到标准错误流。

  2. 输入 4 2,因为除数不为 0,所以程序会输出 4/2=2 到标准输出流,并将结果写入到文件 test.txt 中。



三、控制I/O格式 

(1)流操纵符 

C++ 进行 I/O 格式控制的方式一般有使用流操纵符、设置标志字和调用成员函数。
流操纵符 作用 输入/输出
endl 换行符 输出一个新行符,并清空流 O
ends 输出字符串结束,并清空流 O
flush 清空流缓冲区 O
dec *(默认) 以十进制形式输入或输出整数 I/O
hex 以十六进制形式输入或输出整数 I/O
oct 以八进制形式输入或输出整数 I/O
ws 提取空白字符 O
fixed 以普通小数形式输出浮点数
scientific 以科学计数法形式输出浮点数
left 左对齐,即在宽度不足时将填充字符添加到右边
right * 右对齐,即在宽度不足时将填充字符添加到左边
setbase(int b) 设置输出整数时的进制,b 为 8、10 或 16
setw(int w) 指定输出宽度为 w 个字符,或输入字符串时读入 w 个字符。一次有效
setfill(int c) 在指定输出宽度的情况下,输出的宽度不足时用 ASCII 码为 c 的字符填充(默认情况是用空格填充)
setprecision(int n) 设置输出浮点数的精度为 n 。
在使用非 fixed 且非 scientific 方式输出的情况下,n 即为有效数字最多的位数:如果有效数字位数超过 n ,则小数部分四舍五入,或自动变为科学计数法输出并保留一共 n 位有效数字;
在使用 fixed 方式和 scientific 方式输出的情况下,n 是小数点后面应保留的位数。
setiosflags(fmtfalgs f) 通用操纵符。将格式标志 f 所对应的格式标志位置为 1
resetiosflags(fmtfalgs f) 通用操纵符。将格式标志 f 所对应的格式标志位置为 0(清除)
boolapha 把 true 和 false 输出为字符串
noboolalpha * 把 true 和 false 分别输出为 1 和 0
showbase 输出表示数值进制的前缀
noshowbase * 不输出表示数值进制的前缀
showpoint 总是输出小数点
noshowpoint * 只有当小数部分存在时才显示小数点
showpos 在非负数值中显示 +
noshowpos * 在非负数值中不显示 +
skipws * 输入时跳过空白字符
noskipws 输入时不跳过空白字符
uppercase 十六进制数中使用’A’~’E’。
若输出前缀,则前缀输出“0x”,科学计数法中输出’E’
no uppercase * 十六进制数中使用’a’~’e’。
若输出前缀,则前缀输出“0x”,科学计数法中输出’e’
internal 数值的符号(正负号)在指定宽度内左对齐,数值右对齐,中间由填充字符填充

【示例】 C++ 中输出整数的不同进制表示方法

【示例代码】

#include <iostream>
#include <iomanip>  // 包含 setbase 函数,用于输出不同进制的整数
using namespace std;

int main() {
    int n = 65535, m = 20;

    // 1)分别输出一个整数的十进制、十六进制和八进制表示
    cout << "1)" << n << "=" << hex << n << "=" << oct << n << endl;

    // 2)使用 setbase 分别输出一个整数的十进制、十六进制和八进制表示
    cout << "2)" << setbase(10) << m << "=" << setbase(16) << m << "=" << setbase(8) << m << endl;

    // 3)使用 showbase 和 setbase 分别输出一个整数的十进制、十六进制和八进制表示
    cout << "3)" << showbase;  // 输出表示数值进制的前缀
    cout << setbase(10) << m << "=" << setbase(16) << m << "=" << setbase(8) << m << endl;

    return 0;
}

【代码详解】

  • 在第一部分中,使用 cout,分别输出整数 n 的十进制、十六进制和八进制表示。 hex 和 oct 是 <iomanip> 库中的流控制符,用于指定输出十六进制和八进制数值。
  • 在第二部分中,使用 setbase 函数设置当前输出的进制基数,然后分别输出整数 m 的十进制、十六进制和八进制表示。
  • 在第三部分中,首先使用 showbase 控制符输出表示进制数值的前缀,然后使用 setbase 函数分别输出整数 m 的十进制、十六进制和八进制表示。
  • 需要注意的是,C++ 默认输出的整数为十进制表示,如果需要输出其它进制,可以使用流控制符和 setbase 函数来实现。
  1. #include <iostream> 和 #include <iomanip>,分别引入输入输出流和控制输出格式的库。

  2. using namespace std;,使用 std 命名空间。

  3. int main() { ,程序入口。

  4. int n = 65535, m = 20;,定义两个整型变量 n 和 m

  5. cout << "1)" << n << "=" << hex << n << "=" << oct << n << endl;,先输出序号 1),然后输出整数 n 的十进制、十六进制和八进制表示,使用 hex 和 oct 控制符指定输出不同进制的数值。

  6. cout << "2)" << setbase(10) << m << "=" << setbase(16) << m << "=" << setbase(8) << m << endl;,先输出序号 2),然后使用 setbase 函数分别设置输出的进制基数为 10、16 和 8,输出整数 m 的十进制、十六进制和八进制表示。

  7. cout << "3)" << showbase;,先输出序号 3),然后使用 showbase 控制符输出表示进制数值的前缀。

  8. cout << setbase(10) << m << "=" << setbase(16) << m << "=" << setbase(8) << m << endl;,使用 setbase 函数分别设置输出的进制基数为 10、16 和 8,输出整数 m 的十进制、十六进制和八进制表示。

  9. return 0;,返回程序执行结果。

【执行结果】

  • 因为 C++ 默认输出的整数为十进制表示,如果需要输出其它进制,可以使用流控制符和 setbase 函数来实现。
  • setbase 函数的参数为整数进制基数,分别为 10、16 和 8,对应十进制、十六进制和八进制。
  • showbase 控制符用于输出进制前缀,比如 0x 表示十六进制,0 表示八进制。
1)65535=ffff=177777
2)20=14=24
3)20=0x14=024

(2)标志字

标志常量名 含义 输入/输出
ios::skipws 0X0001 跳过输入中的空白 I
ios::left 0X0002 按输出域左对齐,用填充字符填充右边 O
ios::right * 0X0004 按输出域右对齐,用填充字符填充左边 O
ios::internal 0X0008 在符号位或基数指示符后填入字符 O
ios::dec * 0X0010 转换为十进制基数形式 I/O
ios::oct 0X0020 转换为八进制基数形式 I/O
ios::hex 0X0040 转换为十六进制基数形式 I/O
ios::showbase 0X0080 在输出中显示基数指示符 O
ios::showpoint 0X0100 在输出浮点数时必须带小数点和尾部的 0 O
ios::uppercase 0X0200 以大写字母表示十六进制数,科学计数法使用大写字母 E O
ios::showpos 0X0400 正数前加“+”号 O
ios::scientific 0X0800 科学记数法显示浮点数 O
ios::fixed 0X1000 定点形式表示浮点数 O
ios::unitbuf 0X2000 插入操作后立即刷新流 O

【示例】 C++ 中控制输出流格式的方法

【示例代码】

#include <iostream>
#include <iomanip>  // 包含控制输出格式的库
using namespace std;

int main() {
    double x = 12.34;

    // 1) 输出科学计数法和正号
    cout << "1)" << setiosflags(ios::scientific | ios::showpos) << x << endl;

    // 2) 输出定点表示法
    cout << "2)" << setiosflags(ios::fixed) << x << endl;

    // 3) 先清除定点表示法,再输出科学计数法和正号
    cout << "3)" << resetiosflags(ios::fixed)
         << setiosflags(ios::scientific | ios::showpos) << x << endl;

    // 4) 清除要输出正号的标志,只保留科学计数法
    cout << "4)" << resetiosflags(ios::showpos) << x << endl;

    return 0;
}

【代码详解】

  • 需要注意的是,C++ 中使用 setiosflags 和 resetiosflags 函数来设置和清除输出格式控制标志。例如 scientific 和 fixed 控制科学计数法和定点表示法,showpos 控制是否显示正号等。
  1. #include <iostream> 和 #include <iomanip>,分别引入输入输出流和控制输出格式的库。

  2. using namespace std;,使用 std 命名空间。

  3. int main() { ,程序入口。

  4. double x = 12.34;,定义一个双精度浮点型变量 x

  5. cout << "1)" << setiosflags(ios::scientific | ios::showpos) << x << endl;,先输出序号 1),然后使用 setiosflags 函数设置输出格式为科学计数法,并显示正号,最后输出变量 x 的值。

  6. cout << "2)" << setiosflags(ios::fixed) << x << endl;,先输出序号 2),然后使用 setiosflags 函数设置输出格式为定点表示法,最后输出变量 x 的值。

  7. cout << "3)" << resetiosflags(ios::fixed) << setiosflags(ios::scientific | ios::showpos) << x << endl;,先输出序号 3),使用 resetiosflags 函数清除之前的定点表示法标志,然后使用 setiosflags 函数设置输出格式为科学计数法,并显示正号,最后输出变量 x 的值。

  8. cout << "4)" << resetiosflags(ios::showpos) << x << endl;,先输出序号 4),使用 resetiosflags 函数清除之前的显示正号的标志,最后输出变量 x 的值,此时的输出格式为科学计数法。

  9. return 0;,返回程序执行结果。

【执行结果】

  • 根据不同的流控制符,每个输出语句都按照不同的方式输出了变量 x 的值。
  • 在第一条输出语句中,使用了 setiosflags(ios::scientific | ios::showpos) 将输出格式设置为科学计数法并显示正号。因此,输出了 +1.234000e+01
  • 在第二条输出语句中,使用了 setiosflags(ios::fixed) 将输出格式设置为定点表示法。因此,输出了 12.340000
  • 在第三条输出语句中,先使用了 resetiosflags(ios::fixed) 清除定点表示法标志,然后再使用 setiosflags(ios::scientific | ios::showpos) 将输出格式设置为科学计数法并显示正号。因此,输出了 +1.234000e+01
  • 在第四条输出语句中,先使用了 resetiosflags(ios::showpos) 清除显示正号的标志,然后再输出了变量 x 的值,遵循默认的科学计数法格式,因此输出了 1.234000e+01
1)+1.234000e+01
2)12.340000
3)+1.234000e+01
4)1.234000e+01


四、调用cout的成员函数【示例一】

成员函数 作用相同的流操纵符
precision(int np) setprecision(np)
width(int nw) setw(nw)
fill(char cFill) setfill(cFill)
setf(long iFlags) setiosflags(iFlags)
unsetf(long iFlags) resetiosflags(iFIags)

【示例一】C++ 中控制输出流格式的方法

【示例代码】

#include <iostream>
using namespace std;

int main() {
    double values[] = {1.23, 20.3456, 300.4567, 4000.45678, 50000.1234567};

    cout.fill('*');  // 设置填充字符为星号*
    for (int i = 0; i < sizeof(values) / sizeof(double); i++) {
        cout << "values[" << i << "]=(";
        cout.width(10);  // 设置输出宽度
        cout << values[i] << ")" << endl;
    }

    cout.fill(' ');  // 设置填充字符为空格
    int j;
    for (j = 0; j < sizeof(values) / sizeof(double); j++) {
        cout << "values[" << j << "]=(";
        cout.width(10);  // 设置输出宽度
        cout.precision(j + 3);  // 设置保留有效数字
        cout << values[j] << ")" << endl;
    }

    return 0;
}

【代码详解】

  1. #include <iostream>,引入输入输出流的库。
  2. using namespace std;,使用 std 命名空间。

  3. int main() { ,程序入口。

  4. double values[] = {1.23, 20.3456, 300.4567, 4000.45678, 50000.1234567};,定义一个双精度浮点型数组 values,并初始化其中的数值。

  5. cout.fill('*');,使用 fill 函数将输出中宽度之外的部分填充字符设置为星号 *

  6. for (int i = 0; i < sizeof(values) / sizeof(double); i++) {...},遍历 values 数组中的每个元素,输出其值。使用 cout.width 函数设置输出宽度,并用 * 填充宽度之外的部分。

  7. cout.fill(' ');,清除填充字符的设置,使输出中宽度之外的部分使用空格填充。

  8. for (j = 0; j < sizeof(values) / sizeof(double); j++) {...},遍历 values 数组中的每个元素,输出其值。使用 cout.width 函数设置输出宽度,并用空格填充宽度之外的部分。同时使用 cout.precision 函数设置保留有效数字的位数。

  9. return 0;,返回程序执行结果。

【执行结果】

  • 根据设置的不同输出格式,每个输出语句都按照不同的方式输出了数组 values 中的元素。
  • 在第一段输出中,使用 cout.fill('*') 将输出控制符的填充字符设置为星号 *。然后使用 cout.width(10) 将输出宽度设置为 10,再通过 cout << values[i] 输出数组元素的值。由于输出宽度为 10,小数点后的数字没有被填充完整,所以被星号 * 填充。
  • 在第二段输出中,使用 cout.fill(' ') 将输出控制符的填充字符设置为空格。然后使用 cout.width(10) 将输出宽度也设置为 10。通过 cout.precision(j + 3) 将浮点数保留的有效数字的位数设置为 j + 3。由于整数位数和保留的有效数字位数不同,因此每次迭代输出的数字的宽度也不同。
values[0]=(*****1.23)
values[1]=(**20.3456)
values[2]=(*300.4567)
values[3]=(4000.45678)
values[4]=(50000.1********)
values[0]=(      1.230)
values[1]=(     20.346)
values[2]=(    300.457)
values[3]=(   4000.457)
values[4]=(  50000.123)

【示例二】C++ 中控制输出流的方法

【示例代码】

#include <iostream>
using namespace std;

int main() {
    char c = 'a', str[80] = "0123456789abcdefghijklmn";
    int x = 65;

    cout << "cout.put('a'): ";
    cout.put('a');  // 输出字符 'a'

    cout << "\ncout.put(c + 25): ";
    cout.put(c + 25);  // 输出字符 'z' ('a' + 25 = 'z')

    cout << "\ncout.put(x): ";
    cout.put(x);  // 输出字符 'A' (65 对应 ASCII 码为 'A')

    cout << "\ncout.write(str, 20): ";
    cout.write(str, 20);  // 将 str 的前 20 个字节写入到输出流中

    return 0;
}

【代码详解】

  • 需要注意的是,cout.put 函数可用于把一个字符写到输出流中,而 cout.write 函数用于写入一个字符串或字符数组。使用这两种函数时要特别注意控制字符数组或字符串的长度,以防止越界或写入无效数据。
  1. #include <iostream>,引入输入输出流的库。

  2. using namespace std;,使用 std 命名空间。

  3. int main() { ,程序入口。

  4. char c = 'a', str[80] = "0123456789abcdefghijklmn";,定义一个字符 c 和一个字符数组 str,并分别赋初值。

  5. cout.put('a');,使用 cout.put 函数输出字符 'a'

  6. cout.put(c + 25);,使用 cout.put 函数输出字符 'z',因为将字符变量 c 的 ASCII 码值加上 25 的结果是字符 'z'

  7. cout.put(x);,使用 cout.put 函数输出字符 'A',因为将整型变量 x 的值 65 对应的 ASCII 码值是字符 'A'

  8. cout.write(str, 20);,使用 cout.write 函数将字符数组 str 的前 20 个字符写入到输出流中。

  9. return 0;,返回程序执行结果。

【执行结果】

  • 根据不同的输出控制符,每个输出语句都按照不同的方式输出了变量的值。
  • 在第一条输出语句中,使用了 cout.put('a') 将字符 ‘a’ 写入到输出流。因此,输出了字符 ‘a’。
  • 在第二条输出语句中,使用了 cout.put(c + 25) 将字符 ‘z’ 写入到输出流。因为将字符变量 c 的 ASCII 码值加上 25 的结果是字符 ‘z’,而字符变量 c 的初值是 ‘a’,它的 ASCII 码值是 97。因此,输出了字符 ‘z’。
  • 在第三条输出语句中,使用了 cout.put(x) 将字符 ‘A’ 写入到输出流。因为整型变量 x 的初值为 65,对应的 ASCII 码值是字符 ‘A’。因此,输出了字符 ‘A’。
  • 在第四条输出语句中,使用了 cout.write(str, 20) 将字符数组 str 的前 20 个字符写入输出流中。因此,输出了字符串 “0123456789abcdefghij”,其中没有包括字符串的结束符 ‘\0’。
cout.put('a'): a
cout.put(c + 25): z
cout.put(x): A
cout.write(str, 20): 0123456789abcdefghij


五、调用 cin 的成员函数 

istream 类提供了一些公有成员函数,它们可以以不同的方式提取输入流中的数据。

(1)get() 函数 

【示例】从标准输入流(即键盘输入)读取字符,遇到 EOF(文件结束)标记时停止循环,并输出输入字符的总数

【示例代码】在Windows环境下,当进行键盘输入时,在单独的一行按〈Ctrl+Z〉组合键后再按〈Enter〉键就代表文件输入结束:

#include <iostream>
using namespace std;

int main() {
    int n = 0;  // 统计输入字符数
    char ch;

    while ((ch = cin.get()) != EOF) {  // 当文件没有结束时继续进行循环
        cout.put(ch);  // 输出当前读入的字符
        n++;  // 统计输入字符数
    }

    cout << "输入字符共计: " << n << endl;  // 输出输入字符总数
    return 0;
}

【代码详解】

  • 需要注意的是,cin.get() 函数会读取并返回一个字符,如果输入流结束了,它就会返回 EOF(End Of File)标记,此时停止循环。因此,这段代码可以连续读取输入流中的字符直到文件结束,并按原样输出每个读入的字符。
  1. #include <iostream>,引入输入输出流的库。

  2. using namespace std;,使用 std 命名空间。

  3. int main() { ,程序入口。

  4. int n = 0;,定义一个整型变量 n,用于统计输入字符的总数并初始化为 0。

  5. while ((ch = cin.get()) != EOF) { ,使用 cin.get() 逐个读取输入流中的字符,如果读到的字符不是 EOF(文件结束)标记,就继续循环进行读取和处理。

  6. cout.put(ch);,使用 cout.put() 将当前读入的字符 ch 输出到标准输出流(即屏幕)。

  7. n++;,每次读入一个字符 ch,都把变量 n 的值加 1,用来统计输入字符的总数。

  8. },while 循环结束。

  9. cout << "输入字符共计: " << n << endl;,输出输入字符的总数。

  10. return 0;,返回程序执行结果。

【执行结果】

  • 这段程序没有具体的输出,它会等待用户从键盘输入字符,一旦输入字符,就会把它原样输出,并累加计数器 n 的值。当输入 Ctrl + D 来模拟文件结束标记 EOF 后,它会停止程序的执行,并输出输入的字符总数。
  • 注意,最后的输入字符总数不仅包括了 hello 这 5 个字符,还包括了回车符。如果你在 Windows 操作系统下运行程序,输入的回车符将被当做两个字符,即回车符和换行符。因此,执行结果中的字符总数可能会比你预期的多一个字符。
  • 下面是模拟键盘输入 "hello" 的执行结果:
    hello
    输入字符共计: 5

(2)getline() 函数

getline() 成员函数的原型如下: 从输入流中读取 一行字符
istream & getline(char * buf, int bufSize);
  • 其功能是从输入流中的当前字符开始读取 bufSize-1 个字符到缓冲区 buf,或读到 ’\n’ 为止(哪个条件先满足即按哪个执行)。
  • 函数会在buf中读入数据的结尾自动添加串结束标记 '\0’。
istream & getline(char * buf, int bufSize, char delim);
  • 其功能是从输入流中的当前字符开始读取 bufSize-1 个字符到缓冲区 buf,或读到字符 delim 为止(哪个条件先满足即按哪个执行)。
  • 函数会在 buf 中读入数据的结尾自动添加 '\0'。
两者的区别在于:
  • 前者是读到 '\n' 为止,后者是读到指定字符 delim 为止。
  • 字符 '\n' 或 delim 都不会被存入 buf 中,但会从输入流中取走。
  1. 函数 getline() 的返回值是函数所作用的对象的引用。
  2. 如果输入流中 '\n' 或 delim 之前的字符个数达到或超过 bufSize,则会导致读入操作出错,其结果是:虽然本次读入已经完成,但是之后的读入都会失败。

【示例】从标准输入流中读取多行输入,并把每行输入字符原样输出到标准输出流中

【示例代码】

#include <iostream>
using namespace std;

int main() {
    char buf[10];  // 用于存储每行输入字符的缓冲区
    int i = 0;  // 计数器,统计输入的行数

    while (cin.getline(buf, 10)) {  // 读取输入流中每一行的内容
        cout << ++i << ":" << buf << endl;  // 输出当前行号和该行的内容
    }

    cout << "last:" << buf << endl;  // 输出最后一行输入的内容
    return 0;
}

【代码详解】

  • 需要注意的是,cin.getline() 函数会读取并返回一个字符串。如果输入流结束了,它就会返回 0,同时,如果一行的字符超过了缓冲区 buf 的大小,则不会全部读取,本例中最多可以读取 9 个字符。
  • 因此,当输入流中的一行超过 9 个字符时,输入流的读取会停止,并丢弃缓冲区中未读取的部分。同时,本例中输出的最后一行输入字符是在循环结束后输出的,因此,它的值是最后一次执行 cin.getline() 函数读取到的输入字符。
  1. #include <iostream>,引入输入输出流的库。

  2. using namespace std;,使用 std 命名空间。

  3. int main() { ,程序入口。

  4. char buf[10];,定义一个长度为 10 的字符数组 buf,用于存储每行输入字符的缓冲区。

  5. int i = 0;,定义一个整型变量 i,用于统计输入的行数,并初始化为 0。

  6. while (cin.getline(buf, 10)) { ,使用 cin.getline() 函数和缓冲区 buf 的大小 10,逐行读取输入流中的字符。

  7. cout << ++i << ":" << buf << endl;,使用 cout 对象输出当前行号 i 和该行的内容 buf,其中,++i 的前置自增运算符会先将 i 的值加 1,再将结果输出。最后,使用 endl 输出一个换行符。

  8. },while 循环结束。

  9. cout << "last:" << buf << endl;,输出最后一行输入的内容。

  10. return 0;,返回程序执行结果。

【执行结果】

  • 这段程序没有具体的输出,它会等待用户从键盘输入多行字符,并把每行字符按照行号和内容原样输出到屏幕上。最后,它还会输出最后一行输入的内容。
  • 以下示例中每个缓冲区 buf 的长度为 10,但显示的最后一个字符 d 被认为是第二行的开始,并且最后一行的字符被截断。这是因为 cin.getline() 函数会读取并返回一个字符串,读取的字符总数不能超过缓冲区 buf 的大小。根据本例中缓冲区 buf 的长度为 10,所以每行输入的字符数不应该超过 9 个。
  • 这里最后一行的输出 d is a bo 是因为当输入流结束时,buf 中仍然存储着最后一行输入的内容。虽然缓冲区中未读取到的字符已经被丢弃了,但最后一行的剩余字符并没有被清空。
  • 下面是模拟键盘输入 "hello world" 和 "this is a book" 两行字符的执行结果:
hello worl
d
1:hello wor
2:ld
last:d is a bo

(3)eof() 函数 

eof() 成员函数的原型如下:
bool eof( );
  • eof() 函数用于判断输入流是否已经结束。
  • 返回值为 true 表示输入结束。
  • 在应用程序中可以用 eof() 函数 测试是否到达文件尾,当文件操作结束遇到文件尾时,函数返回 1;否则返回 0。

(4)ignore() 函数 

ignore() 成员函数的原型如下:
istream & ignore(int n=1, int delim=EOF);
  • 此函数的作用是跳过输入流中的 n 个字符,或跳过 delim 及其之前的所有字符(哪个条件先满足就按哪个执行)。
  • 两个参数都有默认值。
  • 因此 cin.ignore() 等效于 cin.ignore(1,EOF),即跳过一个字符。
  • 该函数常用于跳过输入中的无用部分,以便提取有用的部分。

【示例】从标准输入流中读取多个由冒号分隔的字符串,并把每个字符串输出到标准输出流中,直到输入流结束

【示例代码】

#include <iostream>
using namespace std;

int main() {
    char str[30];  // 用于存储读取的字符串

    while (!cin.eof()) {  // 当输入流没有结束时进入循环
        cin.ignore(10, ':');  // 从输入流中跳过 10 个字符或到达冒号(:)时停止
        if (!cin.eof()) {  // 如果输入流没有结束
            cin >> str;  // 读取输入流中的一个字符串
            cout << str << endl;  // 输出该字符串到标准输出流
        }
    }

    return 0;
}

【代码详解】

  • 需要注意的是,cin.ignore() 函数并不会读取任何字符,而只是从输入流中跳过指定的字符数或到达指定字符时停止。此外,如果输入流中的冒号 : 少于 10 个字符,则会一直跳过输入流中的字符,直到到达下一个冒号或输入流结束位置。
  1. #include <iostream>,引入输入输出流的库。

  2. using namespace std;,使用 std 命名空间。

  3. int main() { ,程序入口。

  4. char str[30];,定义一个长度为 30 的字符数组 str,用于存储读取的字符串。

  5. while (!cin.eof()) { ,使用 cin.eof() 判断输入流是否结束,如果输入流没有结束,则进入循环。

  6. cin.ignore(10, ':');,使用 cin.ignore() 函数从输入流中跳过 10 个字符或到达冒号 : 时停止,并把跳过的字符丢弃。这一行的作用是跳过冒号之前的字符,以便继续读取冒号之后的字符串。

  7. if (!cin.eof()) { ,如果输入流没有结束,则进入下一个 if 代码块。

  8. cin >> str;,使用 cin 对象从输入流中读取一个字符串,并存储到字符数组 str 中。

  9. cout << str << endl;,使用 cout 对象输出读取到的字符串,并输出一个换行符。

  10. },if 代码块结束。

  11. },while 循环结束。

  12. return 0;,返回程序执行结果。

【执行结果】

  • 这段程序没有具体的输出,它会等待用户从键盘输入多个由冒号 : 分隔的字符串,当输入流结束后,程序会结束运行。
  • 以下示例中,程序使用 cin.ignore() 函数跳过了每个冒号之前的字符,然后读取了每个冒号之后的一个字符串,并将其输出到标准输出流中。由于输入的字符串中有三个冒号,程序会输出三个字符串。
  • 需要注意的是,程序会在键盘输入结束后自动添加一个结束符,所以循环 while (!cin.eof()) 会循环一次后停止。也就是说,循环中最后一次执行的时候,输入流已经结束,程序会直接退出循环并结束运行。这也可以看出来,因为执行结果中没有其他无关内容。

  • 下面是模拟键盘输入 "
    Home: 12345678
    Tel: 12345678901
    Office: 87654321
    " 的执行结果(要求将电话号码转换为如下形式):
    12345678 
    12345678901 
    87654321

(5)peek() 函数 

peek() 成员函数的原型如下:
int peek( );
  • 函数 peek() 返回输入流中的当前字符,但是并不将该字符从输入流中取走 —— 相当于只是“看了一眼” 将要读入的下一个字符,因此叫 “窥视” 。
  • cin.peek() 不会跳过输入流中的空格和回车符。
  • 在输入流已经结束的情况下, cin.peek() 返回 EOF。

Guess you like

Origin blog.csdn.net/qq_39720249/article/details/131394987