目录
一、流类简介
二、标准流对象
三、控制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()
函数中的代码,然后才开始执行重定向的操作,因此输入的数据会先被读入,输出的结果会在重定向后才写入文件中。
#include <iostream>
,引入输入输出流相关的库。using namespace std;
,使用std
命名空间。int main() {
,程序入口。int x, y;
,定义两个整型变量x
和y
。cin >> x >> y;
,从控制台读取两个整数。freopen("test.txt", "w", stdout);
,将标准输出重定向到文件test.txt
,后续所有的输出都会写入到该文件。if (y == 0)
,判断除数是否为 0。cerr << "error." << endl;
,输出错误信息到标准错误流。else
,当除数不为 0 时执行以下代码。cout << x << "/" << y << "=" << x / y << endl;
,输出x/y
的值。return 0;
,返回程序执行结果。【执行结果】
- 这段代码的作用是,读入两个整数
x
和y
,如果y
不为 0,则输出x/y
的值,否则输出错误信息,并将输出结果写入到test.txt
文件中。- 运行时需要在控制台中输入两个整数,如
4 2
,然后程序会在test.txt
文件中生成一行输出4/2=2
。如果输入的除数为 0,如2 0
,则程序会在控制台输出错误信息:error.
,并不会在test.txt
中进行任何输出。
输入 2 0,因为除数为 0,所以程序会输出一个错误信息到标准错误流。
输入 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 函数来实现。
#include <iostream>
和#include <iomanip>
,分别引入输入输出流和控制输出格式的库。
using namespace std;
,使用std
命名空间。
int main() {
,程序入口。
int n = 65535, m = 20;
,定义两个整型变量n
和m
。
cout << "1)" << n << "=" << hex << n << "=" << oct << n << endl;
,先输出序号1)
,然后输出整数n
的十进制、十六进制和八进制表示,使用hex
和oct
控制符指定输出不同进制的数值。
cout << "2)" << setbase(10) << m << "=" << setbase(16) << m << "=" << setbase(8) << m << endl;
,先输出序号2)
,然后使用setbase
函数分别设置输出的进制基数为 10、16 和 8,输出整数m
的十进制、十六进制和八进制表示。
cout << "3)" << showbase;
,先输出序号3)
,然后使用showbase
控制符输出表示进制数值的前缀。
cout << setbase(10) << m << "=" << setbase(16) << m << "=" << setbase(8) << m << endl;
,使用setbase
函数分别设置输出的进制基数为 10、16 和 8,输出整数m
的十进制、十六进制和八进制表示。
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
控制是否显示正号等。
#include <iostream>
和#include <iomanip>
,分别引入输入输出流和控制输出格式的库。
using namespace std;
,使用std
命名空间。
int main() {
,程序入口。
double x = 12.34;
,定义一个双精度浮点型变量x
。
cout << "1)" << setiosflags(ios::scientific | ios::showpos) << x << endl;
,先输出序号1)
,然后使用setiosflags
函数设置输出格式为科学计数法,并显示正号,最后输出变量x
的值。
cout << "2)" << setiosflags(ios::fixed) << x << endl;
,先输出序号2)
,然后使用setiosflags
函数设置输出格式为定点表示法,最后输出变量x
的值。
cout << "3)" << resetiosflags(ios::fixed) << setiosflags(ios::scientific | ios::showpos) << x << endl;
,先输出序号3)
,使用resetiosflags
函数清除之前的定点表示法标志,然后使用setiosflags
函数设置输出格式为科学计数法,并显示正号,最后输出变量x
的值。
cout << "4)" << resetiosflags(ios::showpos) << x << endl;
,先输出序号4)
,使用resetiosflags
函数清除之前的显示正号的标志,最后输出变量x
的值,此时的输出格式为科学计数法。
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; }
【代码详解】
#include <iostream>
,引入输入输出流的库。
using namespace std;
,使用std
命名空间。
int main() {
,程序入口。
double values[] = {1.23, 20.3456, 300.4567, 4000.45678, 50000.1234567};
,定义一个双精度浮点型数组values
,并初始化其中的数值。
cout.fill('*');
,使用fill
函数将输出中宽度之外的部分填充字符设置为星号*
。
for (int i = 0; i < sizeof(values) / sizeof(double); i++) {...}
,遍历values
数组中的每个元素,输出其值。使用cout.width
函数设置输出宽度,并用*
填充宽度之外的部分。
cout.fill(' ');
,清除填充字符的设置,使输出中宽度之外的部分使用空格填充。
for (j = 0; j < sizeof(values) / sizeof(double); j++) {...}
,遍历values
数组中的每个元素,输出其值。使用cout.width
函数设置输出宽度,并用空格填充宽度之外的部分。同时使用cout.precision
函数设置保留有效数字的位数。
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
函数用于写入一个字符串或字符数组。使用这两种函数时要特别注意控制字符数组或字符串的长度,以防止越界或写入无效数据。
#include <iostream>
,引入输入输出流的库。
using namespace std;
,使用std
命名空间。
int main() {
,程序入口。
char c = 'a', str[80] = "0123456789abcdefghijklmn";
,定义一个字符c
和一个字符数组str
,并分别赋初值。
cout.put('a');
,使用cout.put
函数输出字符'a'
。
cout.put(c + 25);
,使用cout.put
函数输出字符'z'
,因为将字符变量c
的 ASCII 码值加上25
的结果是字符'z'
。
cout.put(x);
,使用cout.put
函数输出字符'A'
,因为将整型变量x
的值65
对应的 ASCII 码值是字符'A'
。
cout.write(str, 20);
,使用cout.write
函数将字符数组str
的前 20 个字符写入到输出流中。
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)标记,此时停止循环。因此,这段代码可以连续读取输入流中的字符直到文件结束,并按原样输出每个读入的字符。
#include <iostream>
,引入输入输出流的库。
using namespace std;
,使用std
命名空间。
int main() {
,程序入口。
int n = 0;
,定义一个整型变量n
,用于统计输入字符的总数并初始化为 0。
while ((ch = cin.get()) != EOF) {
,使用cin.get()
逐个读取输入流中的字符,如果读到的字符不是 EOF(文件结束)标记,就继续循环进行读取和处理。
cout.put(ch);
,使用cout.put()
将当前读入的字符ch
输出到标准输出流(即屏幕)。
n++;
,每次读入一个字符ch
,都把变量n
的值加 1,用来统计输入字符的总数。
}
,while 循环结束。
cout << "输入字符共计: " << n << endl;
,输出输入字符的总数。
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 中,但会从输入流中取走。
- 函数 getline() 的返回值是函数所作用的对象的引用。
- 如果输入流中 '\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()
函数读取到的输入字符。
#include <iostream>
,引入输入输出流的库。
using namespace std;
,使用std
命名空间。
int main() {
,程序入口。
char buf[10];
,定义一个长度为 10 的字符数组buf
,用于存储每行输入字符的缓冲区。
int i = 0;
,定义一个整型变量i
,用于统计输入的行数,并初始化为 0。
while (cin.getline(buf, 10)) {
,使用cin.getline()
函数和缓冲区buf
的大小 10,逐行读取输入流中的字符。
cout << ++i << ":" << buf << endl;
,使用cout
对象输出当前行号i
和该行的内容buf
,其中,++i
的前置自增运算符会先将i
的值加 1,再将结果输出。最后,使用endl
输出一个换行符。
}
,while 循环结束。
cout << "last:" << buf << endl;
,输出最后一行输入的内容。
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 个字符,则会一直跳过输入流中的字符,直到到达下一个冒号或输入流结束位置。
#include <iostream>
,引入输入输出流的库。
using namespace std;
,使用std
命名空间。
int main() {
,程序入口。
char str[30];
,定义一个长度为 30 的字符数组str
,用于存储读取的字符串。
while (!cin.eof()) {
,使用cin.eof()
判断输入流是否结束,如果输入流没有结束,则进入循环。
cin.ignore(10, ':');
,使用cin.ignore()
函数从输入流中跳过 10 个字符或到达冒号:
时停止,并把跳过的字符丢弃。这一行的作用是跳过冒号之前的字符,以便继续读取冒号之后的字符串。
if (!cin.eof()) {
,如果输入流没有结束,则进入下一个 if 代码块。
cin >> str;
,使用cin
对象从输入流中读取一个字符串,并存储到字符数组str
中。
cout << str << endl;
,使用cout
对象输出读取到的字符串,并输出一个换行符。
}
,if 代码块结束。
}
,while 循环结束。
return 0;
,返回程序执行结果。【执行结果】
- 这段程序没有具体的输出,它会等待用户从键盘输入多个由冒号
:
分隔的字符串,当输入流结束后,程序会结束运行。- 以下示例中,程序使用
cin.ignore()
函数跳过了每个冒号之前的字符,然后读取了每个冒号之后的一个字符串,并将其输出到标准输出流中。由于输入的字符串中有三个冒号,程序会输出三个字符串。需要注意的是,程序会在键盘输入结束后自动添加一个结束符,所以循环
while (!cin.eof())
会循环一次后停止。也就是说,循环中最后一次执行的时候,输入流已经结束,程序会直接退出循环并结束运行。这也可以看出来,因为执行结果中没有其他无关内容。- 下面是模拟键盘输入
"
Home: 12345678Tel: 12345678901Office: 87654321"
的执行结果(要求将电话号码转换为如下形式):12345678 12345678901 87654321
(5)peek() 函数
peek() 成员函数的原型如下:int peek( );
- 函数 peek() 返回输入流中的当前字符,但是并不将该字符从输入流中取走 —— 相当于只是“看了一眼” 将要读入的下一个字符,因此叫 “窥视” 。
- cin.peek() 不会跳过输入流中的空格和回车符。
- 在输入流已经结束的情况下, cin.peek() 返回 EOF。