• No results found

Driving LEDs

7.3 Branching

7.5.5 Arrays of Pointers

It is also possible to declare arrays of pointers. In such an array, each element itself is also a pointer. An example of a pointer array declaration is given as follows:

int *IntPointers[20];

In this declaration, IntPointers is a constant pointer. It points to the first element of the array of pointers. If we use the de-referencing operator as shown below we will obtain the contents of the first element, which itself is a pointer to an int. Therefore it must be assigned to a compatible pointer variable. Consider the following declaration:

int a;

int *IntPtr;

int *IntPointers[20];

IntPointers is the start address of the array of pointers to int. In other words, it holds a memory address. This location contains a pointer to an int. Thus, the

contents of any element of the array can be assigned to a pointer to an int, such as IntPtr. To obtain the contents of the first element of the IntPointers array, we can de-reference IntPointers. Once de-referenced, it can be assigned to IntPtr as shown in the line below:

IntPtr = *IntPointers; // contents of 1st element

A pointer to an int is stored at the address obtained by de-referencing IntPointers (i.e. *IntPointers). If we need the contents of the location pointed to by this pointer to int, we must de-reference *IntPointers once more to obtain the integer value. Such an integer value can be assigned to an int type variable such as a. Thus:

a = **IntPointers; // Same as a = *IntPtr;

7.5.6 Pointer Arithmetic

As already seen, a pointer variable can be incremented or decremented. Likewise an integer value can be added or subtracted. However, the results produced by pointer arithmetic are different to the results produced by normal arithmetic. Before explaining this further, we should understand where pointer arithmetic is useful.

One-dimensional Arrays

Pointer arithmetic is especially useful for accessing array elements. Consider the example:

int a[5];

Here we have declared an array of 5 integers. The array name a is a constant pointer and it points to the first element of the array. Figure 7-17 shows an example of such an array in memory.

Memory Address

Array Element and its value

600000 a[0] is 4

600002 a[1] is 9

600004 a[2] is 8

600006 a[3] is 3

600008 a[4] is 5

In the example shown in Figure 7-17, the memory address values change by 2 when we move from one address to the next address. This is because we have assumed each integer occupies two bytes. Thus, the element a[0] occupies the addresses 600000 and 600001. The next element a[1] begins at 600002 and so on.

The value of a is 600000. The pointer a is not a variable, it is a constant. It points to the first element of the array and therefore cannot be assigned another value. It can be de-referenced like other pointers as follows:

*a a[0] which is 4

Althougha cannot be changed, we can add an integer value to a to obtain a new value. Thus:

a+1 is a valid expression.

If we interpret this result using normal arithmetic, it evaluates to 600001. However, in pointer arithmetic it evaluates to 600002. Since a is a pointer to an integer, ‘+1’ really means plus one int type data, which is two bytes in our example. The compiler takes into account the size of the data type pointed to by the pointer when evaluating pointer arithmetic expressions. The result a+1 still remains a pointer and points to the next element of the array:

a+1 600002

a+2 600004

a+3 600006

Just like the pointer a, the following three pointers can also be de-referenced:

*(a+1) a[1] which is 9

*(a+2) a[2] which is 8

*(a+3) a[3] which is 3

Use of parentheses is very important in the cases shown above. If the parentheses had not been used, the results would be as follows:

*a+1 a[0]+1 which is 5

*a+2 a[0]+2 which is 6

*a+3 a[0]+3 which is 7

As can be seen from this discussion, pointer arithmetic can be used to access an array element of a one-dimensional array. For the array a, the ith element can be

accessed by:

Two-dimensional arrays

Pointer arithmetic is applied slightly differently to two-dimensional arrays. Consider the example:

int a[3][2];

This declares an array of 6 elements stored in sequential memory as shown in Figure 7-18.

Memory Address

Array Element and its value

600000 a[0][0] is 6 600002 a[0][1] is 7 600004 a[1][0] is 55 600006 a[1][1] is 9 600008 a[2][0] is 3 600010 a[2][1] is 33

Figure 7-18 Two-dimensional array in memory.

As for the case of one-dimensional arrays, the array name a is still a pointer. Its value is 600000. It is a constant and cannot be changed. The difference for two- dimensional arrays is that a points to the first row of elements, not the first element of the array. Therefore, it represents a data size of 2 integers as specified by the second subscript of the array declaration. As a result the pointer a represents 2 integers, i.e. points to 4 bytes of memory. With this in mind, pointer arithmetic works as follows.

a+1 600004 points to the second row a+2 600008 points to the third row

Using this notation, a pointer to the ith row can be obtained by adding

i to a:

a+i points to the ith row

Like any other pointer, these pointers can also be de-referenced. When these pointers are de-referenced, the result is still a pointer:

0 1 1 0 2 Array a[3][2] 55 6 3 9 7 33

*(a+1) 600004 points to the first element of the second row *(a+2) 600008 points to the first element of the third row *(a+i) points to the first element of the (i+1)th row

The size of data pointed to by these de-referenced pointers is no longer an entire row. They now point to elements, which are single integers. Now pointer arithmetic will be based on single integers or two bytes. Thus:

*(a+1) + 1 600006 points to a[1][1] *(a+2) + 1 600010 points to a[2][1]

Therefore, the pointer that points to the jth element of the ith row is: *(a+i) + j points toa[i][j]

By de-referencing the above pointers, the values of the elements can be accessed:

*(*(a+1) + 1) a[1][1] which is 9

*(*(a+i) + j) a[i][j]

The same arguments we presented for two-dimensional arrays can be extended in the same logical manner to higher-dimensional arrays.