views:

451

answers:

10

If I write

int *columns[32];

am I defining an array with 32 pointers to ints?
Or is it a pointer to an array of 32 ints?

How do I differentiate between the two? Is there a difference?

+14  A: 

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.

qrdl
Out of curiosity, do you know where to get `cdecl` ? The capitalist pigs at Apple weren't kind enough to provide one with their developer tools.
Chris Lutz
+1 to you sir, never seen that tool before, reading the man page for it now...
Paul Dixon
@Chris Mac OS X doesn't include cdecl? I thought it is standard tool for all Unixes. You can grab cdecl source from any Linux distro and compile it on Mac OS X - I don't think it has any dependecies (well, maybe readline)
qrdl
It would be very useful, if the link to cdecl download page was added. Bonus if it also includes windows download... :)
Paulius Maruška
@Chris: it's also not in macports nor in fink. Looks like you will have to compile it by hand.
Stefano Borini
@Stefano - Done that. It's rather difficult. I had to hack it up a little to get it to work, but now it works. For anyone interested, I got it from http://packages.debian.org/sid/devel/cdecl but it didn't work out of the box (or even after being patched). All I had to do was comment out a few lines and it compiled.
Chris Lutz
@qrdl: There is also a version of cdecl online for public use: http://cdecl.org/
James McNellis
A: 

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.

Chris Lutz
I'd hardly say understanding declarations requires "language lawyer" status.
GMan
I know, but I could never remember which one it was either, and OS X doesn't have a nice version of `cdecl` installed.
Chris Lutz
Most non-lawyers wouldn't be able to tell you what `void (*(*(*p)[N][M])[O])(char c) = 0;` declares without using `cdecl` or `geordi` or other cheats, i think.
Johannes Schaub - litb
Actually, there's a simple procedure for breaking down hairy declarations, but the restrictions on the comment field make it hard to demonstrate. Simply speaking, find the leftmost identifier and work your way out, remembering that [] and () bind before *. So you start with p, then note that it's a pointer `(*p)` to an N-element array `(*p)[N]` of M-element arrays `(*p)[N][M]` of pointers `(*(*p)[N][M])` to O-element arrays `(*(*p)[N][M])[O]` of pointers `(*(*(*p)[N][M])[O])` to functions taking a char param `(*(*(*p)[N][M])[O])(char c)` and returning void `void (*(*(*p)[N][M])[O])(char c)`
John Bode
@John, sure everything is easy in the end. I personally apply the "to the right then to the left" rule, which works simple too: *p is a* ") -> left" *pointer to* "( -> right" *array of N arrays of M* ") -> left" *pointer to* "( -> right" *array of O* ") -> left" *pointer to* "( -> right" *function taking char* "EOL -> left" *and returning void*. **But** you first have to know these rules and how they interact with the precedences etc. So i think most non-lawyers are lost in this hell of parentheses.
Johannes Schaub - litb
+6  A: 

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.

Michael Foukarakis
you did, thank you
Carson Myers
+5  A: 

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 ints 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 ints. The declaration would have allocated one pointer, but no arrays of ints.

Charles Bailey
I'm not much of a C/C++ user, but the language does interest me. This seems somewhat counter-intuitive, perhaps because I come from a C# background. If you are declaring int (*columns)[32] I'd expect that you get an array of 32 pointers. I percieve it in such a way that the expression in the parenthesis specifies a pointer type, and the array specifier means "32 instances of the type on the left". Thus - 32 pointers. The same goes the other way - if you say int *columns[32] and that brackets bind tighter, then the intuitive way is an array of 32 items, and then a pointer to it.
Vilx-
Why is it the other way around? I've also seen parenthesis-syntax in other places, most notably function pointers. And it doesn't make sense to me there either. How should I think about it so that it would make sense?
Vilx-
Michael Foukarakis
The reason is that C declarations follow the 'declaration matches usage rule'. It means that `int *x` is meant to be read `*x` is an `int`. It's just one way the language could have been described. I find it really helps when you have 2D arrays. If you have `int x[2][4]` then it means that `x[0][3]` is a valid `int`. Having to reverse the index limits between declaration and usage would have lead to a different sort of confusion.
Charles Bailey
The key to understanding how to read all complex C declarations is well-described here by Charles. It all starts with reading `int *x;` as "`*x` is an `int`", **not** "`x` is an `int *`". Apply all the "operators" to the label in the normal order and you end up with the basic type given.
caf
This should be the accepted answer imho. Why was the cdecl one accepted? It doesn't contain any kind of explanation...
Johannes Schaub - litb
@Vilx - Expanding on the "declaration mimics use" discussion above, if you have an array of pointers to int and you want to access an int value, you'd use the expression `*a[i]`; IOW, you find the right array element, then dereference it. Conversely, if you were using a pointer to an array, you'd have to dereference the pointer first and then find the right array element; i.e., `(*a)[i]`. That structure is mirrored in the declaration.
John Bode
A: 

Here are some fun declarations for you:

int *arrayOfIntP[32];
int (*pointerToArrayOf32)[32];

For more fun with multidimensional arrays look at these posts:

Array of pointers to multidimensional arrays

How do I declare a 2d array using new?

Robert S. Barnes
A: 

Take a look at the links below. They explain how to read C Declarations with easy rules. They may come in handy in the future.

Link1 & Link2

erelender
A: 

One trick is to read from right to left.

Given int* cols[32];

  1. You first see cols[32] : this is an array of size 32.
  2. Next you see int*: this is a pointer

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).

Sesh
+5  A: 

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.

John Bode
I really like this answer
Carson Myers
This is one answer where I wish StackOverflow had a "Favorite Answer" feature. :-/ score += 1;
Chris Kaminski
A: 

http://www.lemoda.net/cdecl/

Seth Kingsley
A: 

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.

fseto