1

This is my program:

#include <iostream>

int main()
{
    // open file1.txt
    FILE* file1;
    fopen_s(&file1, "file1.txt", "wb+");

    // write array of 5 integers to file.txt
    int array1[5] { 1, 2, 3, 4, 5 };
    for (int i = 0; i < 5; i++)
    {
        fwrite(array1, sizeof(array1[0]), 5, file1);
    }

    fseek(file1, 0, SEEK_SET);
    int tempValue;
    fread(&tempValue, sizeof(tempValue), 1, file1);
    // fseek(file1, 0, SEEK_CUR);
    fwrite(&tempValue, sizeof(tempValue), 1, file1);
}

At runtime the program crashed with informatoin:

>     Expression ("Flush between consecutive read and write.",                 
>     !stream.has_any_of(_IOREAD))

But if I uncomment fseek(file1, 0, SEEK_CUR); everything would be fine considering file pointer has not been moved. So why is that? I use Visual Studio 2019


P.S. Why this works just fine?

#include <iostream>

int main()
{
    FILE* file1;
    fopen_s(&file1, "data.txt", "wb+");
    int value = 7;
    fwrite(&value, sizeof(value), 1, file1);
    fwrite(&value, sizeof(value), 1, file1);

    fseek(file1, 0, SEEK_CUR);
    fwrite(&value, sizeof(value), 1, file1);
    fread(&value, sizeof(value), 1, file1);
}
Denys_newbie
  • 1,140
  • 5
  • 15
  • file1 is already a pointer, no need to use `&` (address of) – Yvain May 09 '20 at 19:50
  • 5
    The standard requires a positioning operation (such as `fseek()`) between a read and a write, or between a write and a read, on a file stream opened for update. A no-op `fseek(file1, 0, SEEK_CUR)` is fine; the value `1` will be written over `2` in the file. The error message says "you didn't follow the rules". – Jonathan Leffler May 09 '20 at 19:50
  • 1
    Unrelated to your problem, but the first loop write the full contents of the array five times. – Some programmer dude May 09 '20 at 19:50
  • 1
    @Yvain The `fopen_s` function takes a pointer to a `FILE*` as its first argument. – Adrian Mole May 09 '20 at 19:51
  • The error message says "Flush betreen consecutive read and write." Have you tried to [flush](https://en.cppreference.com/w/c/io/fflush) the file between the write and read calls? – Some programmer dude May 09 '20 at 19:53
  • @JonathanLeffler You should post an answer! – Adrian Mole May 09 '20 at 19:53
  • @AdrianMole — I'm feeling too lazy to find the relevant part of the C++ standard where that is stipulated. I could find it in the C standard easily (C11 [§7.21.5.3 The `fopen` function ¶7](http://port70.net/~nsz/c/c11/n1570.html#7.21.5.3p7)). I'm not so familiar with the details of the C++ standard (and I don't have a copy of C++17 or C++20 to quote from). – Jonathan Leffler May 09 '20 at 19:58
  • By the way, if you're programming in C++, why do you use the old C file functions? Without including the correct headers even. And `fopen_s` isn't in the C++ standard (it's in the C standard, but few outside of the Microsoft world ever use it). – Some programmer dude May 09 '20 at 19:59
  • Does it really say "Flush betreen ..."? Please don't make the mistake to retype error messages, copy'n'paste the whole errors verbatim into your question. Also read [ask] and take the [tour]. – Ulrich Eckhardt May 09 '20 at 20:10

1 Answers1

1

Read to write

Pulled from Microsofts C Runtime Library documentation

When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed. (The file is said to be open for "update".) However, when you switch from reading to writing, the input operation must encounter an EOF marker. If there is no EOF, you must use an intervening call to a file-positioning function. The file-positioning functions are fsetpos, fseek, and rewind. When you switch from writing to reading, you must use an intervening call to either fflush or to a file-positioning function.

Changing between read/write operations require a file-position function, In your code snippet, you have:

...
fseek(file1, 0, SEEK_SET);
int tempValue;
fread(&tempValue, sizeof(tempValue), 1, file1);
// fseek(file1, 0, SEEK_CUR);
fwrite(&tempValue, sizeof(tempValue), 1, file1);
...

Since you are changing from read to write, you need to call a file-position function (fsetpos, fseek or rewind).


Write to Read

As for write to read, you will still need to call a file-position function. However to answer why the second code block works, we need to know what fwrite() does on success.

According to the same Microsoft documentation,

... The fwrite function writes up to count items, of size length each, from buffer to the output stream. The file pointer associated with stream (if there is one) is incremented by the number of bytes actually written.

Consider the code that you have provided:

...
FILE* file1;
fopen_s(&file1, "data.txt", "wb+");
int value = 7;
fwrite(&value, sizeof(value), 1, file1);
fwrite(&value, sizeof(value), 1, file1);

fseek(file1, 0, SEEK_CUR);
fwrite(&value, sizeof(value), 1, file1);
fread(&value, sizeof(value), 1, file1);
...

Assuming all fwrite()'s succeed, your file pointer would be at the EOF. Since the input operation encounters EOF, the code block would execute just fine.

However, you should follow guidelines and call fsetpos, fseek or rewind should fwrite fail.


Similar Stackoverflow questions

C standard library corner case

Why is fseek or fflush always required between reading and writing in the update modes?