If I write
int *columns[32];
am I defining an array with 32 pointers to int
s?
Or is it a pointer to an array of 32 int
s?
How do I differentiate between the two? Is there a difference?
If I write
int *columns[32];
am I defining an array with 32 pointers to int
s?
Or is it a pointer to an array of 32 int
s?
How do I differentiate between the two? Is there a difference?
Expanding on a comment to another answer:
There's a fairly straightforward procedure for reading C declarations. Start with the leftmost identifier in the declarator and work your way out, remembering that []
and ()
bind before *
. Given the declaration
int *columns[32];
break it down as
columns -- columns
columns[32] -- is a 32-element array
*columns[32] -- of pointers
int *columns[32] -- to int.
If the declaration had been
int (*columns)[32];
then it would break down as
columns -- columns
(*columns) -- is a pointer
(*columns)[32] -- to a 32-element array
int (*columns)[32] -- of int.
This will also help you build up complex declarations. Suppose you wanted to declare an array of pointers to functions returning pointers to arrays of char:
f -- f
f[N] -- is an N-element array
*f[N] -- of pointers
(*f[N])() -- to functions
*(*f[N])() -- returning pointers
(*(*f[N])())[M] -- to M-element arrays
*(*(*f[N])())[M] -- of pointers
char *(*(*f[N])())[M]; -- to char
cdecl is a nice tool, but after you'd done this exercise a few times, you shouldn't need it.
When in doubt - ask cdecl
$> cdecl
Type `help' or `?' for help
cdecl> explain int *columns[32]
declare columns as array 32 of pointer to int
EDIT In response to comments: I found cdecl source on Google Code Search. It requires GNU readline library. I think it shouldn't be a problem to compile it on Mac OS X or Windows.
You are defining an array of 32 pointers.
To define a pointer to an array of 32 ints you have to do
int (*columns)[32];
The former declaration instantiates an array with space for 32 * sizeof(int). On the other hand, the latter instantiates a single uninitialized pointer which you can then use as follows:
int myintegers[32] = {0, 1, 2, ..., 31};
int (*columns)[32];
columns = &myintegers;
printf("%d\n", (*columns)[2]);
I hope I made the difference a little bit clear.
It is an array of 32 pointers to int
and yes it does matter.
The C grammar rules specify that array access ([]
) binds tighter than dereference (*
) and declarations mirror usage.
The declaration int *columns[32];
means that the expression *columns[n]
(where n
is a number between 0 and 31) is an int
. This expression is the same as *(columns[n])
. The declaration allocates the space for 32 pointers, but there are no int
s allocated and (assuming that this is a function local declaration) none of the pointers are initialized.
Had the declaration been int (*columns)[32];
then the expression (*columns)[n]
would have been an int
, meaning that the *
dereference happens before the array access, so columns would have been a pointer to an array of 32 int
s. The declaration would have allocated one pointer, but no arrays of int
s.
A test program is illustrative, especially to those of us who aren't language lawyers:
$ gcc -x c -
#include <stdio.h>
int main(void)
{
int *columns[32];
printf("%lu\n%lu\n", sizeof(columns), sizeof(columns[0]));
return 0;
}
$ ./a.out
128
4
$
It appears to be an array of pointers.
Here are some fun declarations for you:
int *arrayOfIntP[32];
int (*pointerToArrayOf32)[32];
For more fun with multidimensional arrays look at these posts:
One trick is to read from right to left.
Given int* cols[32];
All that left of array is the type of the elements in the array. So we read it as array of pointers to int (and of count 32).
Refer to Question #5 of A 'C' Test: The 0x10 Best Questions for Would-be Embedded Programmers by Nigel Jones*
a) int a; // An integer
b) int *a; // A pointer to an integer
c) int **a; // A pointer to a pointer to an integer
d) int a[10]; // An array of 10 integers
e) int *a[10]; // An array of 10 pointers to integers
f) int (*a)[10]; // A pointer to an array of 10 integers
g) int (*a)(int); // A pointer to a function a that takes an integer argument and returns an integer
h) int (*a[10])(int); // An array of 10 pointers to functions that take an integer argument and return an integer
*Alas, the original article on embedded.com can no longer be found on their website.