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

news2024/11/18 5:50:02

目录

一、流类简介

二、标准流对象 

三、控制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::skipws0X0001跳过输入中的空白I
ios::left0X0002按输出域左对齐,用填充字符填充右边O
ios::right *0X0004按输出域右对齐,用填充字符填充左边O
ios::internal0X0008在符号位或基数指示符后填入字符O
ios::dec *0X0010转换为十进制基数形式I/O
ios::oct0X0020转换为八进制基数形式I/O
ios::hex0X0040转换为十六进制基数形式I/O
ios::showbase0X0080在输出中显示基数指示符O
ios::showpoint0X0100在输出浮点数时必须带小数点和尾部的 0O
ios::uppercase0X0200以大写字母表示十六进制数,科学计数法使用大写字母 EO
ios::showpos0X0400正数前加“+”号O
ios::scientific0X0800科学记数法显示浮点数O
ios::fixed0X1000定点形式表示浮点数O
ios::unitbuf0X2000插入操作后立即刷新流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。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/687395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高考选什么专业好?适合考公务员的10大热门专业,了解一下!

高考是人生的分水岭&#xff0c;它是青春和未来的交汇处。高考成绩的优劣将对考生未来的发展产生深远的影响。作为学生们人生中重要的一站&#xff0c;高考不仅考验着学生的学业能力&#xff0c;也考验着他们的心理素质和思维能力。 高考结束后&#xff0c;众多考生面临的一个重…

FFmpeg视频转码参数详解

1 固定码率因子crf&#xff08;Constant Rate Factor&#xff09; 固定码率因子&#xff08;CRF&#xff09;是 x264 和 x265 编码器的默认质量&#xff08;和码率控制&#xff09;设置。取值范围是 0 到 51&#xff0c;这其中越低的值&#xff0c;结果质量越好&#xff0c;同…

阿里云docker启动xxljob,部署自己的定时任务

本次安装版本xxl-job-admin:2.3.0 一&#xff1a;创建xxl-job数据库的各种表 作者官方地址 下载sql执行 二&#xff1a;docker拉取xxl-job镜像 docker pull xuxueli/xxl-job-admin:2.3.0 三&#xff1a;docker启动xxl-job服务 docker run -e PARAMS"--spring.datasour…

用C语言实现经典游戏——贪吃蛇

目录 1.游戏实现思想 &#xff08;1&#xff09;定义蛇对象 &#xff08;2&#xff09;食物对象 &#xff08;3&#xff09;分数&#xff1a; &#xff08;4&#xff09;初始化蛇 &#xff08;5&#xff09;初始化食物 &#xff08;6&#xff09;修改控制台光标位置 &…

Spring Data JPA 报 HOUR_OF_DAY: 0 -> 1异常的解决过程和方案

在进行数据查询时&#xff0c;控制台报了Caused by: com.mysql.cj.exceptions.WrongArgumentException: HOUR_OF_DAY: 0 -> 1异常&#xff0c;查询得知&#xff1a;这是由于查mysql库&#xff0c;转换类型为datetime类型的字段引起的。 网上的解决方案有多种&#xff0c;大…

坐标系转换QGIS插件GeoHey

最近要将面要素&#xff08;GCJ02火星坐标系&#xff09;转WGS84&#xff0c;用程序转太麻烦了&#xff0c;找了半天没找到合适的。 插件非常好用&#xff01;&#xff01;&#xff01; 在QGIS中&#xff0c;由极海&#xff08;GeoHey&#xff09;团队提供GeoHey Toolbox插件…

Linux_清理docker容器的log

最近发现服务器硬盘空间满了&#xff0c;就排查了一番&#xff0c;发现有docker容器的log文件占用太多&#xff0c;所以要做一下清理。 首先是要找到docker容器log文件的储存位置。 1、首先在执行了一下 df -Th 命令&#xff0c;发现根目录满了。 2、然后去到根目录下&#xff…

Android项目中接入 Lint代码规范

一、概述 Android Studio 提供了一个名为 Lint 的代码扫描工具,可帮助开发者发现并更正代码结构质量方面的问题,并且无需您实际执行应用,也不必编写测试用例。系统会报告该工具检测到的每个问题并提供问题的描述消息和严重级别,以便开发者可以快速确定需要优先进行的关键改…

Linux下vim的常见命令操作(快速复查)

目录 前言1、Vim常用操作1.1、环境参数1.2、方向1.3、插入命令1.4、定位命令1.5、删除命令1.6、复制和剪切命令1.7、替换和取消命令1.8、搜索和搜索替换命令1.9、保存和退出命令1.10、其他命令1.11、可视模式 前言 本篇文章不面向新手&#xff0c;全文几乎都是命令&#xff0c;…

【Redis】多级缓存之缓存数据同步策略与Canal

目录 一、数据同步策略 1.设置有效期 2.同步双写 3.异步通知 二、Canal 三、监听Canal 一、数据同步策略 缓存数据同步的常见方式有三种&#xff1a; 1.设置有效期 给缓存设置有效期&#xff0c;到期后自动删除。再次查询时更新&#xff0c;他简单、方便&#xff0c;但…

H5学习 (一)--创建工程

文章目录 一、下载安装VS Code二、创建新文件1. 使用cmd N&#xff0c;创建一个文件2. 点击 Select a language&#xff0c;改变文件的编码类型3. 选择HTML 语言模式4. 输入 !按回车键&#xff0c;就会自动生成一个HTML模版5. 右击项目&#xff0c;选择 “Open In Default Bro…

交叉熵、Focal Loss以及其Pytorch实现

交叉熵、Focal Loss以及其Pytorch实现 本文参考链接&#xff1a;https://towardsdatascience.com/focal-loss-a-better-alternative-for-cross-entropy-1d073d92d075 文章目录 交叉熵、Focal Loss以及其Pytorch实现一、交叉熵二、Focal loss三、Pytorch1.[交叉熵](https://pyto…

浅谈商业智能BI的过去、现在和未来

互联网的大发展也在引领各行各业的改变&#xff0c;包括商业智能BI&#xff0c;商业智能BI就是在数字化时代下飞速发展的。商业智能BI与互联网发展的同时&#xff0c;人工智能、大数据、区块链、云计算等新一代信息化、数字化技术也开始进行加速商业智能BI发展及应用&#xff0…

vmareWorkstation-提取vmdk-文件系统

参考博文-CSDN-BugM&#xff08;作者&#xff09;-将vmdk作为硬盘挂载到另一个linux系统的虚拟机上 一、以管理员身份运行wmware-workstation 二、将目的vmdk文件映射到一个linux虚拟机上 选择左下方的添加按钮 添加的文件的路径可以查看需要添加的虚拟机的情况&#xff0c;如…

PXE批量网络装机、PXE无人值守安装

目录 一、批量部署的优点 二、基本部署过程 三、部署pxe网络体系要求 四、搭建PXE远程安装服务器的步骤 1.安装并启用TFTP服务 2.安装并启用dhcp服务 3.准备linux内核、初始化镜像文件 4.准备PXE引导程序 5.安装FTP服务&#xff0c;准备CentOS7安装源 6.配置启动菜单文…

ATA-3090功率放大器在新能源汽车上的应用

随着全球对环境保护和节能减排的重视&#xff0c;新能源汽车正逐渐成为汽车市场的主流。而功率放大器作为电子控制系统中的关键部件之一&#xff0c;也扮演着越来越重要的角色。那么&#xff0c;功率放大器在新能源汽车上的应用有哪些呢&#xff1f; 图&#xff1a;新能源汽车 …

数字IC前端学习笔记:仲裁轮询(五)

相关文章 数字IC前端学习笔记&#xff1a;LSFR&#xff08;线性反馈移位寄存器&#xff09; 数字IC前端学习笔记&#xff1a;跨时钟域信号同步 数字IC前端学习笔记&#xff1a;信号同步和边沿检测 数字IC前端学习笔记&#xff1a;锁存器Latch的综合 数字IC前端学习笔记&am…

聚焦云原生安全|安全专家揭秘如何强化容器威胁检测能力

4月15日&#xff0c;由极狐主办的“当效率遇上安全 一起开启质效升级之旅”活动顺利开展。 作为国内云原生安全领导厂商&#xff0c;安全狗受邀出席此次活动。 厦门服云信息科技有限公司&#xff08;品牌名&#xff1a;安全狗&#xff09;成立于2013年&#xff0c;致力于提供云…

【中危】BootCDN 投毒风险

漏洞描述 BootCDN是免费的前端开源项目 CDN 加速服务&#xff0c;通过同步cdnjs仓库&#xff0c;提供了常用javascript组件的CDN服务。 多个开发者发现在特定请求中&#xff08;如特定Referer及移动端user-agent&#xff09;会返回包含指向union.macoms.la地址的恶意js文件&a…

快速提取地形图坐标到Revit建立场地模型?

一、快速提取地形图坐标到Revit建立场地模型? 1、打开免费三维地形软件&#xff1a; 2、定位项目位置&#xff1a; 3、按步骤提取坐标及高程&#xff1a; 4、保存为csv文件格式&#xff0c;打开CSV文件&#xff0c;删除第一行&#xff1a; 5、打开坐标转换软件&#xff0c;按步…