Reputation: 15561
What is the difference between the following declarations:
int* arr1[8];
int (*arr2)[8];
int *(arr3[8]);
What is the general rule for understanding more complex declarations?
Upvotes: 507
Views: 403792
Reputation: 2567
int *arr1[5]
In this declaration, arr1
is an array of 5 pointers to integers.
Reason: Square brackets have higher precedence over * (dereferncing operator).
And in this type, number of rows are fixed (5 here), but number of columns is variable.
int (*arr2)[5]
In this declaration, arr2
is a pointer to an integer array of 5 elements.
Reason: Here, () brackets have higher precedence than [].
And in this type, number of rows is variable, but the number of columns is fixed (5 here).
Upvotes: 0
Reputation: 767
Here's how I interpret it:
int *something[n];
Note on precedence: array subscript operator (
[]
) has higher priority than dereference operator (*
).
So, here we will apply the []
before *
, making the statement equivalent to:
int *(something[i]);
Note on how a declaration makes sense:
int num
meansnum
is anint
,int *ptr
orint (*ptr)
means, (value atptr
) is anint
, which makesptr
a pointer toint
.
This can be read as, (value of the (value at ith index of the something)) is an integer. So, (value at the ith index of something) is an (integer pointer), which makes the something an array of integer pointers.
In the second one,
int (*something)[n];
To make sense out of this statement, you must be familiar with this fact:
Note on pointer representation of array:
somethingElse[i]
is equivalent to*(somethingElse + i)
So, replacing somethingElse
with (*something)
, we get *(*something + i)
, which is an integer as per declaration. So, (*something)
given us an array, which makes something equivalent to (pointer to an array).
Upvotes: 2
Reputation: 11
The answer for the last two can also be deducted from the golden rule in C:
Declaration follows use.
int (*arr2)[8];
What happens if you dereference arr2
? You get an array of 8 integers.
int *(arr3[8]);
What happens if you take an element from arr3
? You get a pointer to an integer.
This also helps when dealing with pointers to functions. To take sigjuice's example:
float *(*x)(void )
What happens when you dereference x
? You get a function that you can call with no arguments. What happens when you call it? It will return a pointer to a float
.
Operator precedence is always tricky, though. However, using parentheses can actually also be confusing because declaration follows use. At least, to me, intuitively arr2
looks like an array of 8 pointers to ints, but it is actually the other way around. Just takes some getting used to. Reason enough to always add a comment to these declarations, if you ask me :)
edit: example
By the way, I just stumbled across the following situation: a function that has a static matrix and that uses pointer arithmetic to see if the row pointer is out of bounds. Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_ELEM(ar) (sizeof(ar) / sizeof((ar)[0]))
int *
put_off(const int newrow[2])
{
static int mymatrix[3][2];
static int (*rowp)[2] = mymatrix;
int (* const border)[] = mymatrix + NUM_ELEM(mymatrix);
memcpy(rowp, newrow, sizeof(*rowp));
rowp += 1;
if (rowp == border) {
rowp = mymatrix;
}
return *rowp;
}
int
main(int argc, char *argv[])
{
int i = 0;
int row[2] = {0, 1};
int *rout;
for (i = 0; i < 6; i++) {
row[0] = i;
row[1] += i;
rout = put_off(row);
printf("%d (%p): [%d, %d]\n", i, (void *) rout, rout[0], rout[1]);
}
return 0;
}
Output:
0 (0x804a02c): [0, 0]
1 (0x804a034): [0, 0]
2 (0x804a024): [0, 1]
3 (0x804a02c): [1, 2]
4 (0x804a034): [2, 4]
5 (0x804a024): [3, 7]
Note that the value of border never changes, so the compiler can optimize that away. This is different from what you might initially want to use: const int (*border)[3]
: that declares border as a pointer to an array of 3 integers that will not change value as long as the variable exists. However, that pointer may be pointed to any other such array at any time. We want that kind of behaviour for the argument, instead (because this function does not change any of those integers). Declaration follows use.
(p.s.: feel free to improve this sample!)
Upvotes: 16
Reputation: 504203
I don't know if it has an official name, but I call it the Right-Left Thingy(TM).
Start at the variable, then go right, and left, and right...and so on.
int* arr1[8];
arr1
is an array of 8 pointers to integers.
int (*arr2)[8];
arr2
is a pointer (the parenthesis block the right-left) to an array of 8 integers.
int *(arr3[8]);
arr3
is an array of 8 pointers to integers.
This should help you out with complex declarations.
Upvotes: 134
Reputation: 29787
Use the cdecl program, as suggested by K&R.
$ cdecl
Type `help' or `?' for help
cdecl> explain int* arr1[8];
declare arr1 as array 8 of pointer to int
cdecl> explain int (*arr2)[8]
declare arr2 as pointer to array 8 of int
cdecl> explain int *(arr3[8])
declare arr3 as array 8 of pointer to int
cdecl>
It works the other way too.
cdecl> declare x as pointer to function(void) returning pointer to float
float *(*x)(void )
Upvotes: 277
Reputation: 767
I guess the second declaration is confusing to many. Here's an easy way to understand it.
Lets have an array of integers, i.e. int B[8]
.
Let's also have a variable A which points to B. Now, value at A is B, i.e. (*A) == B
. Hence A points to an array of integers. In your question, arr is similar to A.
Similarly, in int* (*C) [8]
, C is a pointer to an array of pointers to integer.
Upvotes: 0
Reputation: 12708
As a rule of thumb, right unary operators (like []
, ()
, etc) take preference over left ones. So, int *(*ptr)()[];
would be a pointer that points to a function that returns an array of pointers to int (get the right operators as soon as you can as you get out of the parenthesis)
Upvotes: 3
Reputation: 11
In pointer to an integer if pointer is incremented then it goes next integer.
in array of pointer if pointer is incremented it jumps to next array
Upvotes: -9
Reputation: 21
I think we can use the simple rule ..
example int * (*ptr)()[];
start from ptr
" ptr
is a pointer to "
go towards right ..its ")" now go left its a "("
come out go right "()" so
" to a function which takes no arguments " go left "and returns a pointer " go right "to
an array" go left " of integers "
Upvotes: 2
Reputation: 291
int *a[4]; // Array of 4 pointers to int
int (*a)[4]; //a is a pointer to an integer array of size 4
int (*a[8])[5]; //a is an array of pointers to integer array of size 5
Upvotes: 29
Reputation: 51
typedef int (*PointerToIntArray)[];
typedef int *ArrayOfIntPointers[];
Upvotes: 5
Reputation: 422172
int* arr[8]; // An array of int pointers.
int (*arr)[8]; // A pointer to an array of integers
The third one is same as the first.
The general rule is operator precedence. It can get even much more complex as function pointers come into the picture.
Upvotes: 479