Reputation: 377
It's easy to find popular conventions for C-style I/O. What's more difficult is finding explanations as to why they are such. It's common to see a read with statements like:
fread(buffer, sizeof(buffer), 1, ptr);
How should a programmer think about using the parameters size and n of fread()?
For example, if my input file is 100 bytes, should I opt for a larger size with fewer n or read more objects of a smaller size?
If the size-to-be-read and n exceed the byte-size of an input file, what happens? Are the excess bytes that were read composed, colloquially speaking, of "junk values"?
Upvotes: 1
Views: 548
Reputation: 153303
size_t fread(void * restrict ptr, size_t size, size_t n, FILE * restrict stream);
How should a programmer think about using the parameters size and n of fread()?
When reading into an array:
size
is the size of called pointer's de-referenced type.
n
in the number of elements.
some_type destination[max_number_of_elements];
size_t num_read = fread(destination, sizeof *destination, max_number_of_elements, inf);
printf("Number of elements read %zu\n", num_read);
if (num_read == 0) {
if (feof(inf)) puts("Nothing read as at end-of-file");
else if (ferror(inf)) puts("Input error occurred");
else {
// since sizeof *destination and max_number_of_elements cannot be 0 here
// something strange has occurred (UB somewhere prior?)
}
For example, if my input file is 100 bytes, should I opt for a larger size with fewer n or read more objects of a smaller size?
In the case, the size of the data is 1, the max count 100.
#define MAX_FILE_SIZE 100
uint8_t destination[MAX_FILE_SIZE];
size_t num_read = fread(destination, sizeof *destination, MAX_FILE_SIZE, inf);
If the size-to-be-read and n exceed the byte-size of an input file, what happens?
The destination is not filled. Use the return value to determine.
Are the excess bytes that were read composed, colloquially speaking, of "junk values"?
No. There values before fread()
remain the same, (as long as the return was not 0 and ferror()
not set). If the destination was not initialized/assigned, then yes, it may be though of as junk.
Separate size, n
allows fread()
to function as desired even if size * n
overflows size_t
math. With current flat memory models, rarely is this needed.
Upvotes: 3
Reputation: 215183
First, the while (!feof(ptr))
is wrong and a really bad anti-pattern. There are situations where it can work, but it's almost always gratuitously more complicted that correct idiomatic usage. The return value of fread
or other stdio read functions already tells you if it didn't succeed, and you usually need to be able to handle that immediately rather than waiting for the next loop iteration to start. If whatever resource you're learning from is teaching this while (!feof(ptr))
thing, you should probably stop trusting it as a source for learning C.
Now, on to your specific question about the size
and n
arguments: having them separate is completely gratuitous and not useful. Just pass the desired length to read for one of them, and 1
for the other. If you want to be able to determine how many bytes were already read if you hit end-of-file or an error, you need to pass 1
for size
and the requested number of bytes as n
. Otherwise, if any read shorter than expected is an error, it sometimes makes sense to switch them; then the only possible return values are 1 and 0 (success and error, respectively).
For an understanding of why it's the case that how you use these two arguments don't matter, all the stdio read functions, including fread
, are specified as if they happened via repeated calls to fgetc
. It does not matter if you have size*n
such calls or n*size
such calls, because multiplication of numbers commutes.
Upvotes: 0