Reputation: 107
This is the code -
int main() {
char c = 'A';
char *p = &c;
char *str = "Hello";
printf("%s %s", p, str);
return 0;
}
The output is as follows
A????? Hello
A?*??? Hello
A?z??? Hello
A???? Hello
A????? Hello
A??y?? Hello
A?*?? Hello
A?Z??? Hello
A?*+?? Hello
A?l?? Hello
A?z?? Hello
A??i?? Hello
A?ʜ?? Hello
Now I know that %s tries to look for a '\0' to stop printing, which is why the char pointer str outputs perfectly.
But what I want to know, is that when we point a char* to a single character, it prints some garbage values after the actual char - how does it decide to stop after 4 or 5 garbage values each time? How does this safety check work? For all it knows, "?" could be a part of the string.
Upvotes: 1
Views: 460
Reputation: 35154
For format "%s"
, the respective parameter must point to a valid C-String, which means it has to fulfill two conditions: (1) it must be of type char*
(or const char*
), and (2) it must point to an object representing a sequence of characters that is terminated by '\0'
within the object's boundaries.
If you do
char c;
char* ptr = &c;
then variable ptr
fulfills only the first condition; it's a char *
, but the object it points to comprises just one character, and if this character is not '\0'
, then the char "sequence" is not terminated within the object's boundaries.
Hence, printf
will access memory outside of the object and thereby yields undefined behaviour. One such behaviour can be that it simply continues reading memory (even if it is not owned) until somewhere a '\0'
is encountered. That's what you are probably observing.
Upvotes: 7
Reputation: 12679
From printf, the conversion specifier s
[emphasis added]:
writes a character string
The argument must be a pointer to the initial element of an array of characters. Precision specifies the maximum number of bytes to be written. If Precision is not specified, writes every byte up to and not including the first null terminator. If the l specifier is used, the argument must be a pointer to the initial element of an array of wchar_t, which is converted to char array as if by a call to wcrtomb with zero-initialized conversion state.
In this statement:
printf("%s %s", p, str);
p
is pointer to a char
type variable c
and you are using %s
format specifier. Note that, if precision is not specified with conversion specifier s
then it writes bytes till it find null terminating character. The %s
format specifier, when writing the bytes pointed by p
, it will writing bytes starting from the memory pointed by p
till it finds the null terminating character. That means, it may access the memory beyond the memory owned by object c
. Reading memory that is not owned by the program is undefined behavior which includes program may execute incorrectly (either crashing or silently generating incorrect results), or it may fortuitously do exactly what the programmer intended.
Instead, you can do:
printf("%.1s %s", p, str);
^^
precision of the conversion
With %.1s
, it will read only one character from the memory location pointed by p
.
Upvotes: 3
Reputation: 1037
That is the magic of "Undefined behaviour". You cannot predict what is going to happen or how it will behave. In different environments, it is more likely to produce different results so...
Upvotes: 1
Reputation: 2286
This will produce different results. Mostly unexpected result. Try running the code in different machine for example different online C compiler. You will be able to see different result. It will be always unexpected.
Upvotes: 1