Файл: Interfacing with C plus plus-programing communication with microcontrolers (K. Bentley, 2006).pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 14.06.2025

Просмотров: 3622

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

7 DRIVING LEDS 167

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

Array Element

Address

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

Figure 7-17 An example of 5 integers in memory.

168 7 DRIVING LEDS

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

Although a 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:

*(a+i)


7 DRIVING LEDS 169

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

Array Element

Address

and its value

600000

0

1

a[0][0] is

6

600002

a[0][1] is

7

0

6

7

600004

a[1][0] is 55

1

55

9

600006

a[1][1] is

9

2

3

33

600008

a[2][0] is

3

Array a[3][2]

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 twodimensional 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:


170 7 DRIVING LEDS

*(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 to a[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.

7.5.7 Pointers to Functions

Pointers can be declared to point to functions. Just like all the pointers discussed previously, function pointers will also have an address in memory. These addresses point to the first instruction to be executed.

An example of a function pointer declaration is:

int (*CalcFunctionPtr)(int,int);

In the above example, the name of the function pointer is CalcFunctionPtr. This pointer can only point to a particular category of function as specified by the pointer declaration. The declaration specifies that the function to be pointed to by CalcFunctionPtr must receive two integer parameters and must return an integer value. An example of a function that can be pointed to by

CalcFunctionPtr is:

int Add(int a, int b)

{

return (a + b);

}

Another function that can be pointed to by the CalcFunctionPtr is:

int Sub(int a, int b)

{


7 DRIVING LEDS 171

return (a – b);

}

In a similar manner to arrays, where the array name is a constant pointer, function names are also constant pointers for the simple reason that when a program is running the location of a function in memory is fixed.

In the above two functions, Add and Sub are two constant function pointers. Each of them point to the first instruction to be executed in their respective functions. These constant pointer values can be assigned to a declared pointer variable. An example program is given in Listing 7-1.

Listing 7-1 Use of pointers to functions.

#include <iostream.h> #include <conio.h>

int Add(int a, int b)

{

return (a + b);

}

int Sub(int a, int b)

{

return (a - b);

}

void main()

{

int a, b, Result; char key;

int (*CalcFunctionPtr)(int,int);

cout << "Enter two integer values " << endl; cin >> a >> b;

cout << "Press '+' or '-' key" << endl;

key = getch(); // getch() reads the key pressed

switch(key)

{

case '+' : CalcFunctionPtr = Add; break;

case '-' : CalcFunctionPtr = Sub;

}

172 7 DRIVING LEDS

Result = CalcFunctionPtr(a,b);

cout << "The result is " << Result << endl;

}

If the ‘+’ key is pressed, the switch statement will set the CalcFunctionPtr to point to the Add() function. If the ‘-‘ key is pressed, CalcFunctionPtr will be set to point to the Sub() function. The second-last line of the code fragment will execute either the Add() function or the Sub() function depending on the key pressed. This is an example where a function pointer is used to carry out different tasks using the same statement for different cases (Result = CalcFunctionPtr(a,b)).

In a more complex program you may have a large portion of the program written using the function pointer variable. If we need to change the cases, we do not need to change the part of the program that calculates the result. The program in Listing 7-2 shows how we can add another case for multiplication and yet the result will be calculated using the same statement as for Listing 7-1; ‘Result =

CalcFunctionPtr(a,b);’.

Listing 7-2 Adding more functionality to the program in Listing 7-1.

#include <iostream.h> #include <conio.h>

int Add(int a, int b)

{

return (a + b);

}

int Sub(int a, int b)

{

return (a - b);

}

int Mult(int a, int b)

{

return (a * b);

}

void main()

{

int a, b, Result; char key;

int (*CalcFunctionPtr)(int,int);

7 DRIVING LEDS 173

cout << "Enter two integer values " << endl; cin >> a >> b;

cout << "Press '+', '-' or '*' key" << endl;

key = getch(); // getch() reads the key pressed

switch(key)

{

case '+' : CalcFunctionPtr = Add; break;

case '-' : CalcFunctionPtr = Sub; break;

case '*' : CalcFunctionPtr = Mult;

}

Result = CalcFunctionPtr(a,b);

cout << "The result is " << Result << endl;

}

Functions Returning Pointers

Functions returning pointers are discussed here since their declarations are similar. A function with the name AnyFunction that receives two int type parameters and returns a pointer to an int is declared as follows:

int *AnyFunction(int,int);

Compare this declaration with the declaration of FunctionPtr, which is a pointer to a function taking two int type parameters and returning an int type value:

int (*FunctionPtr)(int,int);

In one case a pair of parentheses is present and in the other case the parentheses are omitted. Although only slightly different, these two declarations are completely different. AnyFunction is a function name and therefore is a constant pointer. FunctionPtr is a pointer variable.

7.5.8 Pointers to void

Pointers can also be declared to be of type ‘pointer to void’. These pointers do not have any restrictions as to the type of data or functions they can point to. The following example outlines their use.

int

a;

//

declaration

of

an int

float b;

//

declaration

of

a float

void *VoidPtr;

//

declaration

of a void pointer

int

Add(int,int);

//

declaration

of a function