Ph.D. in Computer Science at Rutgers University

Talking about C pointer - Pointer to array, Array of pointers and Two-level pointer

This is the second one of 'Talking about C pointer' series. In this article, I'll discuss the difference between pointer to array, array of pointer and two-level pointer.

Is that correct to use two-level pointer to point to two-dimensional array?

In last article, we've discussed about the relationship between one-dimensional array and pointer.

int a[5] = {1, 2, 3, 4, 5};	// a is an integer array with 5 elements
int *p = a;			// p is a pointer of integer pointing to the first element of array a

If we extend it to two-dimensional array. How to use pointer to refer a two-dimensional array? The first thing in my mind is two-level pointer from deduction. Now let's see whether it is correct:

/* test.c */
#include <stdio.h>

int main() {
	int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};	// two-dimensional array
	int **t = a;    // t is a two-dimensional array of integer

	printf("a = 0x%x\n", a);
	printf("t = 0x%x\n", t);
	printf("t[0] = %d\n", t[0]);
	printf("t[0][0] = %d\n", t[0][0]);	

	return 0;

Let's compile this program in GCC:

gcc -m32 -o test test.c

The result of those codes are: (on x86_64 Linux using -m32 option when compiling)

a = 0x8430de00
t = 0x8430de00
t[0] = 0x1
Segmentation fault (core dumped)

Obvious, it's wrong. Here, a whose type is int(*)[4] means the address of the first one-dimensional array: {1, 2, 3, 4}. a[0] means the addreses of the first element of the first one-dimensional array. And a[0][0] means the first element of this array. However, we assign a to the two-level pointer of integer t, the compiler did an implicit cast from int(*)[4] to int**. t[0] equals to what is stored in the address 0x8430de00, but the type of t[0] is int*, thus the value in 0x8430de00 which is 1 was treated as a integer pointer -- an address stores an integer value. And when we redirect with t[0][0], it refers the value in the address of 0x01, which is not a legal address.

From this case, we could clearly see is not correct to use a two-level pointer to refer an two-dimensional array. Then, what pointers could we use to refer to an two-dimensional array?

int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};	// two-dimensional array

1. Pointer to Array

int (*p)[4] = a;	// p is an array pointer

Pointer to array itself is a poiner, it points to one line of a two-dimension array which is an one-dimension array. In the code above, p is a pointer, thus sizeof(p) = 4 in this case. p directs to one-dimension array a[0] = {1, 2, 3, 4} while *p is both the name of this one-dimension array and the address of the first element of array a[0], thus sizeof(*p) = 16. *(*p+1) is the second element of array a[0]. Even if the value of p and *p are the same, they're totally different.


   * ellipse means address, triangle means value
p = a = &a[0]
*p = &a[0][0]
*(*p+1) = a[0][1] = 2

p+1 = a+1 = &a[1]
*(p+1) = &a[1][0] = a[1]
*(*(p+2)+1) = a[2][1] = 10

2. Array of Pointer

int *q[3];	//q is a pointer array
// need to point to one-dimensional array row by row
for (int i = 0; i < 3; i++) {
	q[i] = a[i];

Array of pointer itself is an array, each element of this array is a pointer. In the code above, q is an array, thus sizeof(q) = 12 in this case. *q is the first element of this array, and it's an integer pointer point to an integer array, thus sizeof(*q) = 4.


   * ellipse means address, triangle means value
*q = a[0]
*(q+1) = a[1]
*(*(q+2)+1) = a[2][1] = 10

3. One-level pointer

int *r = &a[0][0];	// r is a one-level pointer

Two-dimensional array in C language is store in memory with 'row major order', that means two-dimensional array will stored in serial row by row. Therefore we could use one-level pointer to direct a two-dimensional array.


r+1 = &a[0][1]
r+4 = &a[1][0]
*(r+9) = a[2][1] = 10


Pointer to array, array of pointer and two-level pointer are three different things although they're often confused. Pointer to array and array of pointer could be used to refer to an two-dimensional array. In next talk, we'll cover dynamic memory allocation concerning pointers.