Why do these yield the same result?
uint8_t header[HEADER_SIZE];
fread(&header, sizeof(uint8_t), HEADER_SIZE, input);
fwrite(&header, sizeof(uint8_t), HEADER_SIZE, output);
uint8_t header[HEADER_SIZE];
fread(header, sizeof(uint8_t), HEADER_SIZE, input);
fwrite(header, sizeof(uint8_t), HEADER_SIZE, output);
In the first version, would the &
not give access just to the location of the array, and not the array itself like in the second version? Were it a single valuable I understand why an &
would be used, but I assumed an array is itself a "pointer", generally speaking, so there would be no reason to get its address again? Is it just redundancy in that case?
CodePudding user response:
The function fread
is declared the following way
size_t fread(void * restrict ptr, size_t size,
size_t nmemb,
FILE * restrict stream);
Its first parameter has the unqualified type void *
(actually the parameter type is the qualified type void * restrict
) . A pointer to object of any type may be assigned to a pointer of the type void *
.
The expression &header
has the pointer type uint8_t ( * )[HEADER_SIZE]
and yields the initial address of the extent of memory occupied by the array,
The expression header
used as an argument of a call of fread
is implicitly converted to a pointer of the type uint8_t *
and yields the same initial address if the extent of memory occupied by the array.
Thus these calls
fread(&header, sizeof(uint8_t), HEADER_SIZE, input);
fwrite(header, sizeof(uint8_t), HEADER_SIZE, output);
are equivalent in sense that the function fread
gets the same values for its parameters.
Consider the following simple demonstration program.
#include <stdio.h>
int main( void )
{
char s[6] = "Hello";
printf( "The value of the expression s is %p\n", ( void * )s );
printf( "The value of the expression &s is %p\n", ( void * )&s );
}
The program output might look like
The value of the expression s is 0x7fffa4577a2a
The value of the expression &s is 0x7fffa4577a2a
As you can see the both outputted values are equal each other though in the first call the used argument expression has the type char *
while in the second case the used argument expression has the type char ( * )[6]
.
However if you will write for example
#include <stdio.h>
int main( void )
{
char s[6] = "Hello";
printf( "%s\n", s );
printf( "%s\n", &s );
}
then the compiler can issue a message for the second call of printf
that the function expects an argument of the type char *
instead of the type char ( * )[6]
though the both values of the expressions are equal each other.
CodePudding user response:
header
is an array of char
. Passing an array as an argument effectively passes a pointer to its first element, fread
and fwrite
accept pointers to void
as their first argument so fread(header, sizeof(uint8_t), HEADER_SIZE, input);
is fine although for consistency with the array definition it would be safer to write:
fread(header, sizeof(*header), HEADER_SIZE, input);
&header
has a different type: pointer to one or more arrays of HEADER_SIZE
characters (uint8_t (*)[HEADER_SIZE]
). Since fread
accepts any kind of pointer, the compiler will accept the call fread(&header, sizeof(uint8_t), HEADER_SIZE, input);
without a warning.
Because header
and &header
have the same address, fread
will behave as expected, albeit this behavior is not guaranteed by the C Standard. Note however that if header
was a pointer to char
, passing &header
would produce a very different result, undefined behavior indeed as the value of the pointer would be overwritten and probably many more bytes beyond...