A question about printf arguments. C/C++
Question
We have the following code fragment:
char tab[2][3] = {'1', '2', '\0', '3', '4', '\0'};
printf("%s\n", tab);
And I don't understand why we don't get an error / warning in the call to I DO get a warning but not an error, and the program runs fine. It prints 'printf
.12
'.
printf
is expecting an argument of type char *
, i.e. a pointer to char
. So if I declared char arr[3]
, then arr
is an address of a memory unit which contains a char
, so if I called printf
with it, it would decay to pointer to char, i.e. char *
.
Analogously, tab
is an address of a memory unit that contains the type array of 3 char's which is in turn, an address of memory unit contains char
, so tab
will decay to char **
, and it should be a problem, since printf
is expecting a char *
.
Can someone explain this issue?
Addendum:
The warning I get is:
a.c:6: warning: char format, different type arg (arg 2)
Solution
Example Source
#include <stdio.h>
int main( void ) {
char tab[2][3] = {'1', '2', '\0', '3', '4', '\0'};
printf("%s\n", tab);
return 0;
}
Compile Warning
$ gcc test.c test.c: In function ‘main’: test.c:5: warning: format ‘%s’ expects type ‘char *’, but argument 2 has type ‘char (*)[3]’
Pointers are Pointers
The %s
argument to printf
indicates to the function that it will be receiving a pointer (to a string). A string, in C, is merely a series of bytes terminated by an ASCII-Z. The tab[2][3]
variable is a pointer. Some compilers will issue a warning about the pointer mismatch. However, the code should still print out 12
because printf
's code traverses memory starting at the pointer it was given (printing characters as it goes) until it finds a zero byte. The 1, 2, and \0 are contiguously set in memory, starting at the address represented by the tab
variable.
Experiment
As an experiment, what happens when you compile and run the following code:
#include <stdio.h>
int main( void ) {
char tab[2][3] = {'1', '2', '\0', '3', '4', '\0'};
printf("%s\n", tab[1]);
return 0;
}
Don't be afraid of experimenting. See if you can come up with the answer based on what you now know. How would you reference tab
now (in light of the experiment) to get rid of the warning and still display 12
?
OTHER TIPS
The tab parameter matches the elipsis in the printf() call. C and C++ compilers are undfer no obligation to check such parameters.
Your assumption that tab
will decay to char **
is wrong: tab
has type char [2][3]
, ie it will decay to char (*) [3]
. It's important to understand that although arrays and pointers often behave alike, they are not the same thing. printf()
expects a char *
, so it takes the bits of the char (*) [3]
and interprets them accordingly. Although it works on your platform, the C standard doesn't guarantee this: both pointers reference the same memory location, but their representation need not be identical.
Check my answer to this related question for details.
You seem to have explained it yourself, I don't see what's left to say.
tab
is an array of two char *
's. Each element of tab
is a string that printf
can accept, but tab
itself is not acceptable, since it is a pointer to a pointer to a char.