I stumbled upon a question with this code
int arr[10];
scanf("%s", arr);
printf("%s", arr);
I don't know the purpose, and I'm perfectly aware of how much this code smells. But my question here is if this i legal, and if I can expect it to reprint the string I enter? (Provided that the input string isn't so long that it causes buffer overflow)
And I also wonder if there's any example where this is actually useful.
From the C standard about fprintf https://port70.net/~nsz/c/c11/n1570.html#7.21.6.1p8
If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.
and fscanf https://port70.net/~nsz/c/c11/n1570.html#7.21.6.2p12
If no l length modifier is present, the corresponding argument shall be a pointer to the initial element of a character array large enough to accept the sequence and a terminating null character, which will be added automatically.
And in this case, it's not a character array. But I seem to recall that there are some special rules about implicit conversions to and from char pointers, but I also have a memory that these does not apply to variadic functions.
CodePudding user response:
For the language lawyer I would say it is illegal:
From C11: 7.21.6.
s
If nol
length modifier is present, the argument shall be a pointer to the initial element of an array of character type. 280)
and
9 If a conversion specification is invalid, the behavior is undefined. 282) If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
For any practical use I would say that I cannot think of a scenario where it might fail as long as you don't enter more characters than fit into the array.
Update after question was extended:
But I seem to recall that there are some special rules about implicit conversions to and from char pointers, but I also have a memory that these does not apply to variadic functions.
Correct, implicit conversions can only happen if type of destination is known. For variadic functions no such conversion is done for pointers.
And also in those cases where an implicit conversion would be done, it is only possible if one of them is void *
, not between int *
and char *
.
CodePudding user response:
... that there are some special rules about implicit conversions to and from char pointers
No, that's not correct.
For void pointers you have implicit conversion but not for char pointers. In the very old K&R days (i.e. before "void" was introduced) char pointers were used as "the generic pointer" type but still there was no implicit conversion.
Maybe you are confusing conversion with aliasing. For aliasing char pointers are special as a char pointer is allowed to alias other object types.
The conclusion is that the code has undefined behavior. Passing an int pointer when a char pointer is expected is not standard compliant.
CodePudding user response:
You are allowed to access an int
or an array of int
using char
references; C 2018 6.5 7 says character types may be used to access an object.
However, for %s
, scanf
and printf
should be passed a char *
, not an int *
. Even though a char *
may be used (with dereferencing) to access an int
or array of int
, that does not mean an int *
will serve in place of a char *
. When scanf
or printf
attempts to get the char *
they expect (as by using va_arg
), the fact that an int *
was passed makes the behavior not defined by the C standard.
If instead you convert the int *
to a char *
:
scanf("%s", (char *) arr);
printf("%s", (char *) arr);
then the behavior is arguably defined by the C standard. (“Arguably” because the internals of scanf
and printf
are not formally specified. Presumably they align with the aliasing rules in 6.5 7.)
CodePudding user response:
The program will run but with a little warning explaing that '%s' expects the variable arr to be a char * type otherwise an array of char. So, the output will be the string that the user types on demand of the program...