Question 1
My question is, how come this doesn't work for a two-dimensional array?
Answer
for (k=0; k<=g_count-1; k++)
sum += *(g+k);
is wrong on two counts.
*(g+k) does not evaluate to an int.
*(g+k) accesses the array out of bounds when k > 1.
When g is declared as:
int g[2][4];
g decays to a pointer of type int (*)[4]. It does not decay to a pointer of type int*.
What type does g+k evaluate to? It also evaluates to a pointer of type int (*)[4].
Where does it point to? It will be helpful to see that with a diagram.
|<--- memory used by g -->|
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
address of g
|
v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
address of g[0] address of g[1]
| |
v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
When used in an expression, g decays to the address of g[0].
The expression g evaluates to the address of g[0].
The expression g+1 evaluates to the address of g[1].
g g+1 g+2
| | |
v v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
As you can see, g+k points to a location beyond the valid limits when k > 1. Derefercencing g+k will lead to undefined behavior when k > 1.
You could use:
int* ptr = &g[0][0]; // Pointer to the first int in the 2D array.
for (k=0; k<=g_count-1; k++)
sum += *(ptr+k);
// ^^^ ptr, not g
That will be valid use of the array and the pointers.
Question 2
I've noticed that while &g[0][0] and g hold the same value, &g[0][0]+1 and g+1 do not. Can someone please explain why?
Answer
Given the array, we have:
g g+1
| |
v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
&g[0][0]
| &g[0][0]+1
| |
v v
+---+---+---+---+---+---+---+---+
| | | | | | | | |
+---+---+---+---+---+---+---+---+
From the diagram, you can see why expressions g and &g[0][0] evaluate to the same address. However, the type of the expressions are not the same. The expression g evaluates to int (*)[4] while &g[0][0] evaluates to int*.
Since the type of the expression g is int (*)[4], the offset between g and g+1 is the same as the size of 4 ints.
Since the type of the expression &g[0][0] is int*, the offset between &g[0][0] and &g[0][0]+1 is the same as the size of one int.
That explains why g+1 does not evaluate to the same address as &g[0][0]+1 even though g and &g[0][0] evaluate to the same address.