如何将 stdin 返回到控制台?

问题描述

我可能在这里遗漏了一些东西,但是否可以将 stdin 更改为文件指针,然后将其切换回控制台?

示例:

stdin = fp;
for (int x; x < 10; x++)
{
   c = getchar()
}
stdin = ??? // Return the stream to the console

解决方法

“官方”答案是freopen()。理论上可以调用

freopen("somefile","r",stdin);

现在 stdin 正在读取 "somefile"。但是,一旦完成此操作,完成后让 stdin 指向标准输入(或者,如您所称的“控制台”)要么很棘手,要么是不可能的。另请参阅旧 12.33 中的问题 12.34C FAQ list

但实际上:您为什么要尝试以这种方式重新分配 stdinstdin 基本上是一个全局变量,只要你有模式

change global variable;
make function call that implicitly uses global variable;
set global variable back to what it was;

你的设计很差,而且容易酿成大祸。通常你想要做的是在中间创建一个该函数调用的修改版本——不管它是什么——让你在中将某些东西作为显式参数传递,而不是隐式地使用全局变量。

在这种情况下,您甚至不需要发明任何新东西,因为除了 getchar() 从全局 stdin 隐式读取之外,您只需调用 getc(fp),它读取从您要指定的任何文件指针:

for (int x; x < 10; x++)
{
   c = getc(fp);
}
,

先将其保存在另一个变量中。

FILE *save_stdin = stdin;
stdin = fp;
...
stdin = save_stdin;

当然,在第一种情况下可能不需要更改 stdin。您可以只使用 getc(fp) 而不是 getchar()。仅当您调用使用 stdin 且无法更改的代码时,才需要重新分配 stdin

,

根据man stdin

由于符号 stdin、stdout 和 stderr 被指定为 宏,分配给它们是不可移植的。标准流可以是 在库函数的帮助下引用不同的文件 freopen,特别引入,使重新分配标准输入成为可能, 标准输出和标准错误。

所以,这样做是不安全的。 但是,您可以使用带有输入流文件描述符和读取模式的 fdopen 来恢复 stdin,如下所示:

stdin = fdopen(0,"r");

在下面的代码中,第一个循环从文件示例中读取数据,第二个循环从标准输入中读取字符:

FILE *fp = fopen("example.txt","r");

char c;
stdin = fp;
while ((c = fgetc(stdin)) != EOF) {
    printf("%c",c);
}    

stdin = fdopen(0,"r");
while ((c = fgetc(stdin)) != EOF) {
    printf("%c",c);
}

fclose(fp);
return 0;