A recent question prompted a discussion centering on arrays and pointers. The question was in reference to scanf("%s", &name)
vs scanf("%s", name)
.
For the following code, Microsoft actually resolves this for you in VS2010 (and maybe earlier versions?),
#include <stdio.h>
int main()
{
char name[30];
printf("Scan \"name\" - ");
scanf("%s", name);
printf("Print \"&name\" - %s\n", &name);
printf("Print \"name\" - %s\n", name);
printf("Pointer to &name - %p\n", &name);
printf("Pointer to name - %p\n", name);
printf("\n\n");
printf("Scan \"&name\" - ");
scanf("%s", &name);
printf("Print \"&name\" - %s\n", &name);
printf("Print \"name\" - %s\n", name);
printf("Pointer to &name - %p\n", &name);
printf("Pointer to name - %p\n", name);
return 0;
}
Is this actually defined in the ANSI C Standard, or is this allowed to be compiler dependent? Does this work because MS is treating everything as C++? Please ignore buffer overflow issues for now.
Both name
and &name
should give the same result. Strictly speaking, only name
is valid per the C language standard and &name
results in undefined behavior, so you should definitely use name
, but in practice both will work.
name
is an array, so when you use it as an argument to a function (as you do when you pass it to printf
), it "decays" to a pointer to its initial element (which is a char*
here).
&name
gives you the address of the array; this address is the same as the address of the initial element (because there can be no padding bytes before the initial element of an array or between elements in an array), so &name
and name
have the same pointer value.
However, they have different types: &name
is of type char (*)[30]
(a pointer to an array of 30 char
) while name
, when it decays to a pointer to its initial element, is of type char*
(a pointer to a char
, in this case, the initial char
element of the array name
).
Since they have the same value and since the printf
and scanf
functions reinterpret the argument as a char*
anyway, there should be no difference whether you pass name
or &name
.
Undefined Behaviour as per the Standard.
The printf conversion specifier "%p"
expects a void*
: anything else invokes UB
The printf conversion specifier "%s"
expects a char*
that includes a null byte somewhere inside the object pointed to: anything else invokes UB
The scanf conversion specifier "%s"
expects a char*
with enough space for the input and an extra null terminating byte: anything else invokes UB
If any implementation defines the behaviour, then it should be ok to use in that implementation.
Most often printing a char*
or a char(*)[30]
instead of a void*
with printf("%p")
results in a UB manifestation that is indistinguishable from the intended behaviour.
Most often printing a char(*)[30]
instead of a char*
with printf("%s")
results in a UB manifestation that is indistinguishable from the intended behaviour.
From what you say, it appears MS manifestation of UB in these cases is the same as intended.
But it's still Undefined Behaviour.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With