Idr
Idr

Reputation: 6250

(*b)[0] vs *b[0] - Arrays and pointers

I'm working through toy problems to understand the differences between pointers and arrays in C and I've stumbled upon something I'm not yet able to grok or find an answer to.

I have the following program

#include <stdio.h>

int main()
{
    int a[3][3] = {{1, 2, 3}, {4, 5,6}, {7, 8, 9}};
    int (*b)[3];

    b = a;

    printf("%d %d %d\n", (*b)[0], (*b)[1], (*b)[2]);
    printf("%d %d %d\n", *b[0], *b[1], *b[2]);

    b++;
    printf("%d %d %d\n", (*b)[0], (*b)[1], (*b)[2]);

    b++;
    printf("%d %d %d\n", (*b)[0], (*b)[1], (*b)[2]);

    return 0;
}

And when I compile and run it I get this:

me@mac: clang -g q.c -o q.o                                                                     
me@mac: ./q.o
1 2 3
1 4 7
4 5 6
7 8 9

My question is what's the difference between (*b)[0] and *b[0]? It appears that the former is of type int * while the latter is of type int *[3]. How to interpret the operators *[]() to grok this?

Upvotes: 4

Views: 133

Answers (6)

D&#233;j&#224; vu
D&#233;j&#224; vu

Reputation: 28830

A bit late to the party, but answers seem to miss some important points.

what is the difference between (*b)[0] and *b[0]?

provided that b is a pointer arrays of 3 int, and points to a.

int (*b)[3] = a; // int a[3][3]

to avoid some confusion, let say that a and b are

int a[X][Y];     // in your example, X=Y=3
int (*b)[Y] = a; // this line probably gives some clue about what b is

This is a matter of precedence. [] takes precedence over *, meaning that

  • if you don't put the parents to *b[0], b[0] is evaluated first and yields a int [Y], the first [Y] array of [X][Y], then * is applied and decays (dereferences) into an int, the first int of that array of Y.
    Result (or target) is the int in a[0][0].

  • with the parents, (*b)[0], *b is evaluated first yielding a int [Y], the first one, then the [0] gives the first int of that [Y].
    Result (or target) is the int in a[0][0]. Again... really?

But the two [0] are not the same thing! The confusion comes from both the * and [0] yield to the first element, however the order of evaluation is different in both cases.

Upvotes: 0

haccks
haccks

Reputation: 106012

b is a pointer to an array of 3 ints. In the assignment

b = a;  

a will decay to pointer to its first element. Since a is an array of arrays, its first element is and array of 3 ints. Therefore, the above statement is equivalent to

b = &a[0];

So, b is pointing to array a[0]. The elements of array a[0] can be accessed by using index a[0][i]. In pointer arithmetic equivalent it is *(*(a + 0) + i) = *(*(a) + i) = *(*a + i) = (*a)[i].
In the expression (*a)[i] the type of a after conversion is int (*)[3] which is also the type of b. Therefore, array a[0] can also be accessed by using (*b)[i].
So, the statement

printf("%d %d %d\n", (*b)[0], (*b)[1], (*b)[2]);  

is equivalent to

printf("%d %d %d\n", (*a)[0], (*a)[1], (*a)[2]);   

or

printf("%d %d %d\n", a[0][0], a[0][1], a[0][2]);   

Now look at *b[0]. As per operator precedence rule, *b[0] is equivalent to *(b[0]). Simply b[0] is representing array a[0] as discussed above and array converted to pointer to its first element when used in an expression, with some exception there, b[0] is actually a pointer to element a[0][0] in the expression *(b[0]). * out of () dereferencing this pointer and giving the value present at &a[0][0]. Similarly, *b[1] and *b[2] are giving the elements at the address &a[1][0] and &a[2][0].
Therefore, the statement

printf("%d %d %d\n", *b[0], *b[1], *b[2]);  

is equivalent to

printf("%d %d %d\n", *a[0], *a[1], *a[2]);    

or

printf("%d %d %d\n", &a[0][0], &a[0][1], &[0][2]);

This results in a conclusion that both (*b)[0] and *b[0] are of same type, int.

Upvotes: 0

Mohan
Mohan

Reputation: 1901

My question is what is the difference between (*b)[0] and *b[0]?

int (*b)[3] ; is pointer to one dimensional array of size 3 In this case it first dereference the pointer and then do index access because of ().

*b[3] is array of 3 pointers, In this case first do index access because of [ ];

because of that when you doing

printf("%d %d %d\n", (*b)[0], (*b)[1], (*b)[2]);

printf("%d %d %d\n", *b[0], *b[1], *b[2]);

in first printf it is printing element of first one dimensional array in second printf it is pointing to first element of each row.

after b++ in first case pointing to second array and second printf it is pointing to second element of each row.

Upvotes: 1

Sami Kuhmonen
Sami Kuhmonen

Reputation: 31153

This only applies to two-dimensional arrays, not to any random pointers.

When using (*b)[1] the dereferencing is done first and then the indexing, so it actually means b[0][1] and you are getting values from the first array.

If you use *b[1] it is the same as *(b[1]). The indexing operator will be handled first and the the dereferencing, so you get b[1][0].

Upvotes: 2

Lundin
Lundin

Reputation: 213799

int (*b)[3]; is an array pointer, a special kind of pointer that can point to a whole array and not just to the first element. Not to be confused with int *b[3] which is an array of 3 pointers and not present in your code.

b=a sets b to point to the first element in the 2D array a, which is a 1D array.

When you dereference an array pointer, you get the array. And when an array is used in an expression, it "decays" into a pointer to the first element, which explains the first printf line.

If you write *b[0], then [] has higher operator precedence than *, so it means "give me array number 0, it will decay into a pointer to the first element, give me the contents of that element".

For any pointer type, array pointers included, pointer increments of b follow the rules of pointer arithmetic: increase the address so that the pointer points at the next adjacent item of pointed-at-type in memory. That is, increase the address with sizeof(*b) bytes, which will be 3*sizeof(int) in this example.

Upvotes: 3

MikeCAT
MikeCAT

Reputation: 75062

(*b)[0] first dereference the pointer and then do index access. It is equivalent to *((*b)+(0)).

*b[0] first do index access and then dereference the pointer. It is equivalent to **((b)+(0)).

Adding zero means virtually nothing, so both of them are equivalent to **b with type int, so there are virtually no difference.

Upvotes: 0

Related Questions