Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does the "size" argument in fread() refer to?

Tags:

c

fread

I'm trying to make a basic program which copies the header of a .wav file, this was my attempt:

#include <stdio.h>
#include <stdint.h>

int main (void)
{
    FILE* input = fopen("input.wav", "r");
    FILE* output = fopen("output.wav", "w");
    
    uint8_t header [44];
    
    fread(header, sizeof(uint8_t), 44, input);
    fwrite(header, sizeof(uint8_t), 44, output);
    
    fclose(input);
    fclose(output);
}

However, after failing to make it work, I looked up how to do it and apparently

fread(header, sizeof(uint8_t), 44, input);
fwrite(header, sizeof(uint8_t), 44, output);

should be

fread(header, 44, 1, input);
fwrite(header, 44, 1, output);

This is very confusing to me, as I thought that the second argument was supposed to be the size of the type of data unit you want to fread. Can anyone help me understand what I'm missing? Many thanks.

like image 559
BlueKhakis Avatar asked Nov 29 '25 03:11

BlueKhakis


2 Answers

The first size parameter specifies the size of a single record. The second size parameter defines how many records you want to load. fread returns the number of records it loaded.

So if you have a structure which is 20 bytes, and you have a file where you have stored 5 of the records then you can pass it like this.

if(fread(ptr, 20, 5, strm) != 5)
    printf("Unable to load 5 records\n");

Alternativaly you could load the same file like this:

if(fread(ptr, 1, 5*20, strm) != 5*20)
    printf("Unable to load 5 records\n");

The effect is the same, but the first version is more readable, because usually you may read records not just "bytes". It's easier to understand in the context of your application logic. And of course you don't have to deal with calculating the number of bytes yourself, thus reducing a chance for errors.

The same applies to fwrite.

So in your above example I would rather write it like this:

  // Your header is 44 bytes long (which is sizeof) but you want to read ONE header
  if(fread(header, sizeof(header), 1, input) != 1)
     ... error reading 1 header ....
like image 56
Devolus Avatar answered Nov 30 '25 15:11

Devolus


sizeof(uint8_t) is guaranteed to be 1 . Some people think it good style to use the sizeof expression instead of the number.

You can either write 44 "blocks" of size 1, or 1 block of size 44. In either case , you tried to write 44 bytes -- the writing part is the same either way.

The difference is in the return value, which reports how many blocks were successfully written. So if you use the 1, 44 order then it will tell you exactly how many bytes were written. If you use the 44, 1 order then you will either get 0 or 1 as the return value (and no way to know if it partially succeeded).

The same consideration applies to fread.


The FILE* input = fopen("input.wav", "r"); part is incorrect: this specifies to open the file in text mode, which may perform translations on the input, such as changing the line endings.

Instead, open in binary mode with "rb" mode string.

like image 35
M.M Avatar answered Nov 30 '25 17:11

M.M



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!