The relevant part of the code snippet is:
char T[2];
scanf("%s", &T);
&T
is a pointer to the array of two characters (char (*)[2]
). This is not the type that scanf
needs for a %s
specifier: it needs a pointer to a character (char *
). So the behavior of the program is undefined.
The correct way to write this program, as you know, is
char T[2];
scanf("%s", T);
Since T
is an array, when it is used in most contexts, it “decays” to a pointer to the first character: T
is equivalent to &(T[0])
which has the type char *
. This decay does not happen when you take the address of the array (&T
) or its size (sizeof(T)
).
In practice, almost all platforms use the same representation for all pointers to the same address. So the compiler generates exactly the same code for T
and &T
. There are some rare platforms that may generate different code (I've heard of them but I couldn't name one). Some platforms use different encodings for “byte pointers” and “word pointers”, because their processor natively addresses words, not bytes. On such platforms, an int *
and a char *
that point to the same address have different encodings. A cast between those types converts the value, but misuse in something like a variable argument list would result in the wrong address. I would expect such platforms to use byte addresses for a char array, however. There are also rare platforms where a pointer encodes not only the address of the data, but also some type or size information. However, on such platforms, the type and size information would have to be equivalent: it's a block of 2 bytes, starting at the address of T
, and addressable byte by byte. So this particular mistake is unlikely to have any practical impact.
Note that it would be completely different if you had a pointer instead of an array in the first place:
char *T; // known to point to an array of two characters
scanf("%s", &T); // bad
Here &T
is a pointer to the location in memory that contains the address of the character array. So scanf
would write the characters that it reads at the location where the pointer T
is stored in memory, not at the location that T
points to. Most compilers analyze the format string of functions like printf
and scanf
and so would emit an error message.
Note that char T[2]
only has room for two characters, and this includes the null byte at the end of the string. So scanf("%s", T)
only has room to read a single character. If the input contains more than one non-whitespace character at this point, the program will overflow the buffer. To read a single character and make it a one-character string, use
char T[2];
scanf("%c", T);
T[1] = 0;
Unlike scanf("%s", T)
, this reads any character, even whitespace. To read a string with a length limit, add a limit to the %s
specification. You should never use an unlimited %s
in scanf
since this will read as much input as is available, regardless of how much room there is to store this input in memory.
char T[2];
scanf("%1s", T); // one less than the array size