Search code examples
cfilefreadfseek

Why does fread() give seemingly random data?


I have the following C code that opens a file in rb+ mode, then writes 100 bytes of value 0. When I read the file with an offset of anything other than 0, I get 96. Why is this?

FILE *fp = fopen("myfile", "rb+");
rewind(fp);
char zero = 0;
fwrite(&zero, 1, 100, fp);
char result;
fseek(fp, 1, SEEK_SET);
fread(&result, 1, 1, fp);
printf("%d\n", result);

I'm on Linux x64 using GCC.


Solution

  • From your clarification in the comments, your intent was to write 100 zero bytes to the file. There are at least two and possibly three ways to do this.

    The first is to allocate an array of 100 zero-initialized bytes, and write that:

    char zeroes[100] = { 0 };
    fwrite(zeroes, sizeof(char) /* == 1 */, sizeof(zeroes), f);
    

    This doesn't scale well if you want to write, say, 10,000 or 10,000,000 zero bytes. You could also do this:

    char zero = 0;
    for (int i = 0; i < 100; ++i) fwrite(&zero, sizeof(char), 1, f);
    

    This scales better, but performs very badly since it's always more efficient to do a single large write than many tiny writes. Instead, you can seek to a later position in the file, and then write only the last byte. On POSIX systems, this is guaranteed to fill the earlier unwritten portion of the file with zeroes:

    char zero = 0;
    fseek(f, 99, SEEK_SET);
    fwrite(&zero, sizeof(char) /* == 1 */, 1, f);
    

    I believe the zero-fill guarantee is also given for Windows' MSVCRT runtime, but I can't immediately find proof of that on MSDN (this might make a good question). If someone knows whether Windows, other platforms, and/or some version(s) of the C standard itself make or do not make this guarantee, this answer could be improved.

    Of course, if you are on a POSIX system and don't need portable code, you can use ftruncate() which makes the same guarantee without even needing to do an fwrite(). Windows has SetEndOfFile() but that function fills the extended portion of the file with undefined values, not zero bytes.