When working with arrays and pointers in C, one quickly discovers that they are by no means equivalent although it might seem so at a first glance. I know about the differences in L-values and R-values. Still, recently I tried to find out the type of a pointer that I could use in conjunction with a two-dimensional array, i.e.
int foo[2][3];
int (*a)[3] = foo;
However, I just can’t find out how the compiler “understands” the type definition of a in spite of the regular operator precedence rules for * and []. If instead I were to use a typedef, the problem becomes significantly simpler:
int foo[2][3];
typedef int my_t[3];
my_t *a = foo;
At the bottom line, can someone answer me the questions as to how the term int (*a)[3] is read by the compiler? int a[3] is simple, int *a[3] is simple as well. But then, why is it not int *(a[3])?
EDIT: Of course, instead of “typecast” I meant “typedef” (it was just a typo).
First, you mean "typedef" not "typecast" in your question.
In C, a pointer to type
Tcan point to an object of typeT:The above is simple to understand. Now, let’s make it a bit more complex. You seem to know the difference between arrays and pointers (i.e., you know that arrays are not pointers, they behave like them sometimes though). So, you should be able to understand:
But for completeness’ sake: in the assignment, the name
ais equivalent to&a[0], i.e., a pointer to the first element of the arraya. If you are not sure about how and why this works, there are many answers explaining exactly when the name of an array "decays" to a pointer and when it does not:I am sure there are many more such questions and answers on SO, I just mentioned some that I found from a search.
Back to the topic: when we have:
foois of type "array[2]of array[3]ofint". This means thatfoo[0]is an array of 3ints, andfoo[1]is an array of 3ints.Now let’s say we want to declare a pointer, and we want to assign that to
foo[0]. That is, we want to do:The above is no different in form to the
int *pa = a;line, because the types ofaand offoo[0]are the same. So, we needint *p;as our declaration ofp.Now, the main thing to remember about arrays is that "the rule" about array’s name decaying to a pointer to its first element applies only once. If you have an array of an array, then in value contexts, the name of the array will not decay to the type "pointer to pointer", but rather to "pointer to array". Going back to
foo:The name
fooabove is a pointer to the first element offoo, i.e., we can write the above as:The type of
foo[0]is "array[3]ofint". So we needqto be a pointer to an "array[3]ofint":The parentheses around
qare needed because[]binds more tightly than*in C, soint *q[3]declaresqas an array of pointers, and we want a pointer to an array.int *(q[3])is, from above, equivalent toint *q[3], i.e., an array of 3 pointers toint.Hope that helps. You should also read C for smarties: arrays and pointers for a really good tutorial on this topic.
About reading declarations in general: you read them "inside-out", starting with the name of the "variable" (if there is one). You go left as much as possible unless there is a
[]to the immediate right, and you always honor parentheses.cdeclshould be able to help you to an extent:To read
For
For
(Example from c-faq question 1.21. In practice, if you are reading such a complicated declaration, there is something seriously wrong with the code!)