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 printf. I DO get a warning but not an error, and the program runs fine. It prints '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)

Was it helpful?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top