1
int main(){

    int a,b;

    std::cin >> a >> b;           // first

    freopen("test.txt","r",stdin);
    std::cin >> a >> b;           // second
    fclose(stdin);
    cout << a << ", " << b << endl;

    freopen("test2.txt","r",stdin);
    std::cin >> a >> b;          // third
    fclose(stdin);
    cout << a << ", " << b << endl;

    std::cin >> a >> b;          // fourth

    return 0;
}

This block of code is to have a mixture of input from terminal and files. The first, second and third cin works fine, but the fourth failed. It seems that fclose(stdin) has no function here.

Yukun Xia
  • 65
  • 7
  • 1
    `stdin` and `cin` are typically going to be the same file. How did you expect to be able to read from a file after you closed it? – Nate Eldredge Mar 21 '19 at 02:47
  • Similar to [this question](https://stackoverflow.com/questions/5257509/freopen-equivalent-for-c-streams). – Perette Mar 21 '19 at 03:18

1 Answers1

0

According to the c++ draft 27.4.2:

The object cin controls input from a stream buffer associated with the object stdin, declared in <cstdio>.

Reading from std::cin is the same as reading from stdin. This means that after fclose(stdin) using std::cin is like calling scanf("%d", &a).

This is exactly what happens in the third case, where fclose(stdin) is called before reading std::cin. In contrast, cases 1-3 the code reads std::cin before fclose(stdin).

Reading from a closed stdin is possibly undefined. Here is what the c11 draft has to say about it:

7.21.7.1 The fgetc function

...

int fgetc(FILE *stream);

...

Returns: If the end-of-file indicator for the stream is set, or if the stream is at end-of-file, the end- of-file indicator for the stream is set and the fgetc function returns EOF. Otherwise, the fgetc function returns the next character from the input stream pointed to by stream. If a read error occurs, the error indicator for the stream is set and the fgetc function returns EOF.

This text covers all cases of reading from an open stdin (successful, end-of-file, and a read error), but they don't refer to the case when the stream is closed due to fclose. I could not find anything in the standard that covers this case, which means that the case is undefined.

Conclusion: reading from std::cin after fclose(stdin), without any further freopen is undefined behavior. Trying to read a closed C stream might refer to freed resources.

Michael Veksler
  • 8,217
  • 1
  • 20
  • 33
  • Thank you so much! But I can also reach this conclusion after my tiny test. So what confused me now is how to make my std::cin return to receiving words from terminal. Do you know how to achieve that? – Yukun Xia Mar 22 '19 at 04:39
  • @ysgc you can save the original stdin descriptor before you start `saved_fd = strdup(0)`, and when you finally need to restore stdin, you `close(0)` and then `strdup(saved_fd)`. But don't forget to clear any eof and error flags and the buffered data. – Michael Veksler Mar 22 '19 at 07:15
  • Hi Michael, I tried : saved_fd = strdup(0); close(0); But the close function is not defined, do I need to include some head file? – Yukun Xia Mar 23 '19 at 00:20