另类IO

另类IO

1. stdin 和 stdout (标准输入/输出)

在计算机程序中,标准输入 (stdin)标准输出 (stdout) 是两个预定义好的数据流,它们是程序与外部环境进行基本数据交互的通道。

  • stdin (Standard Input,标准输入):通常情况下,stdin 默认连接到计算机的键盘。程序可以从这个流中读取数据。例如,当您在命令行运行一个程序,并且程序需要您输入一些信息时,您在键盘上输入的内容就会通过 stdin 传递给程序。在 C++ 中,我们通常使用 cingetchar() 等函数从标准输入读取数据。源文件提到 getchar() 函数的作用是从终端(键盘)获取输入的字符。
  • stdout (Standard Output,标准输出):通常情况下,stdout 默认连接到计算机的显示器(控制台)。程序可以将处理结果或需要显示的信息输出到这个流中。例如,一个计算程序将结果显示在屏幕上,就是通过 stdout 实现的。在 C++ 中,我们通常使用 coutputchar()printf() 等函数将数据输出到标准输出。源文件提到 putchar() 函数的作用是向终端(显示器)输出字符,并给出了使用 cout 输出多行中文字符串的例子。

2. C++ 中的标准 I/O 流

C++ 的 <iostream> 库提供了用于处理标准输入输出的对象,并且通过 using namespace std; 可以更方便地使用它们:

  • cin (console input):是与 stdin 关联的输入流对象。您可以使用提取运算符 >>cin 中读取数据。例如,cin >> a; 会从标准输入读取一个值并存储到变量 a 中。源文件指出,输入/输出的各变量之间应使用 >><< 分隔。同时需要注意的是,cin 在读取一行字符串时,遇到空格就会停止。可以使用 getline() 函数读取包含空格的整行字符串。
  • cout (console output):是与 stdout 关联的输出流对象。您可以使用插入运算符 << 将数据输出到 cout。例如,cout << "Hello" << endl; 会将字符串 “Hello” 和换行符输出到标准输出。源文件给出了使用 cout 输出各类字符的例子,并强调输出语句应严格按照格式编写,例如不能写成 cout << a + b = c

3. C 风格的标准 I/O 函数

C 语言的 <cstdio> 库(在 C++ 中也可以使用 <stdio.h><cstdio>)提供了一些与标准输入输出相关的函数:

  • scanf()printf():是格式化输入输出函数,它们也与 stdinstdout 关联。scanf() 用于从标准输入读取指定格式的数据,printf() 用于向标准输出输出指定格式的数据。源文件给出了 scanf()printf() 的一般格式和使用示例,并强调了 scanf() 需要使用取地址符 & 来接收变量的地址。同时提到了 printf() 的格式控制与 scanf() 类似,并给出了常用的格式字符,如 %d(十进制整数)、%o(八进制数)、%x(十六进制数)等 [我的前一次回复, 24]。
  • getchar()putchar():是用于单个字符输入输出的函数,它们也与 stdinstdout 关联。getchar() 从标准输入读取一个字符,putchar() 将一个字符输出到标准输出。源文件给出了使用 getchar()putchar() 的简单示例 以及在递归程序中逆序输出字符的例子。

4. 文件 I/O 流

C++ 的 <fstream> 库提供了用于文件输入输出的类,可以看作是对标准输入输出概念的扩展,用于操作磁盘文件:

  • ifstream (input file stream):用于从文件中读取数据,类似于从 stdin 读取。您需要创建一个 ifstream 对象并关联到一个文件,然后使用提取运算符 >>getline() 等函数读取文件内容。
  • ofstream (output file stream):用于向文件中写入数据,类似于向 stdout 输出。您需要创建一个 ofstream 对象并关联到一个文件,然后使用插入运算符 << 等将数据写入文件。

5. I/O 重定向

I/O 重定向是指改变程序默认的标准输入和标准输出流的来源和去向。例如,您可以将程序的输入从键盘重定向到一个文件,或者将程序的输出从屏幕重定向到一个文件。

5.1 使用 freopen() 函数进行重定向

C 语言的 <cstdio> 库提供的 freopen() 函数可以将一个已有的标准流(如 stdin、stdout、stderr)与一个指定的文件关联起来,实现重定向。函数原型如下:

#include <iostream>
#include <cstdio>
using namespace std;

int main() {
    freopen("input.txt", "r", stdin); // 将标准输入重定向到 input.txt 文件

    int num;
    cin >> num; // 从 input.txt 文件读取数据

    cout << "读取到的数字是:" << num << endl;

    fclose(stdin); // 关闭文件流(可选)
    return 0;
}

在这个例子中,程序不再从键盘等待输入,而是会尝试打开名为 input.txt 的文件,并将该文件的内容作为标准输入流。

#include <iostream>
#include <cstdio>
using namespace std;

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

    cout << "这是一行输出到文件的数据。" << endl;
    printf("这也是一行通过 printf 输出到文件的数据。\n");

    fclose(stdout); // 关闭文件流(可选)
    return 0;
}

在这个例子中,程序使用 coutprintf 输出的内容将不会显示在控制台上,而是会被写入到名为 output.txt 的文件中。

源文件的第三章大量使用了 freopen() 函数,特别是在模拟竞赛环境下的题目中。例如,在“求中间数”的题目中,程序使用 freopen("mid.in", "r", stdin); 将标准输入重定向到 mid.in 文件,并使用 freopen("mid.out", "w", stdout); 将标准输出重定向到 mid.out 文件。这符合编程竞赛的要求,代码需要从指定文件读取输入数据,并将结果写入指定文件。

源文件还强调,要成功运行使用了文件重定向的程序,必须在程序的同一文件目录下创建相应的输入文件(例如 mid.in),并且包含符合题目要求的输入数据。

需要注意的是,使用 freopen() 进行重定向通常在程序的开始阶段进行,并且在程序结束时,标准流可能需要使用 fclose() 关闭。

5.2 使用 ifstreamofstream 进行文件 I/O (实现重定向)

您也可以直接使用 ifstreamofstream 对象进行文件输入输出,这相当于更明确地进行了 I/O 的“重定向”。

#include <iostream>
#include <fstream>
#include <string>
using namespace std;

int main() {
    ifstream inputFile("input.txt"); // 创建输入文件流对象并关联到 input.txt

    if (inputFile.is_open()) {
        string line;
        while (getline(inputFile, line)) { // 从文件读取每一行
            cout << "从文件读取到:" << line << endl;
        }
        inputFile.close(); // 关闭文件流
    } else {
        cerr << "无法打开输入文件!" << endl;
        return 1;
    }

    return 0;
}

在这个例子中,我们创建了一个 ifstream 对象 inputFile 并将其与 input.txt 文件关联。程序直接从 inputFile 读取数据,而不是从 cin (stdin) 读取。

#include <iostream>
#include <fstream>
using namespace std;

int main() {
    ofstream outputFile("output.txt"); // 创建输出文件流对象并关联到 output.txt

    if (outputFile.is_open()) {
        outputFile << "这是通过文件流写入文件的一行数据。" << endl;
        outputFile << 123 << " " << 45.6 << endl;
        outputFile.close(); // 关闭文件流
    } else {
        cerr << "无法打开输出文件!" << endl;
        return 1;
    }

    return 0;
}

在这个例子中,我们创建了一个 ofstream 对象 outputFile 并将其与 output.txt 文件关联。程序直接将数据写入 outputFile,而不是输出到 cout (stdout)。

总结

  • stdinstdout 是程序与外部交互的基本通道,默认连接到键盘和控制台。
  • C++ 使用 cincout(以及 C 风格的 scanf, printf, getchar, putchar)来操作标准输入输出流。通过加入 using namespace std; 可以简化代码。
  • I/O 重定向允许您改变这些流的来源和去向。
  • freopen() 函数可以将标准流重定向到文件。这在编程竞赛中非常常用,用于从指定输入文件读取数据并将结果写入指定输出文件。
  • ifstreamofstream 类提供了更直接的文件输入输出方式,通过创建文件流对象并与文件关联,您可以实现从文件读取数据和向文件写入数据,这本质上也是一种 I/O 的“重定向”。

理解这些概念和方法对于进行文件操作以及应对编程竞赛等需要特定输入输出方式的场景至关重要。源文件中的大量例题也展示了这些 I/O 操作和重定向技巧的应用。