Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Interfacing with C plus plus-programing communication with microcontrolers (K. Bentley, 2006)

.pdf
Скачиваний:
192
Добавлен:
12.08.2013
Размер:
3.18 Mб
Скачать

154 7 DRIVING LEDS

if (<cond. exp. 1>)

{

if (<cond. exp. 2>)

{

<true clause>

}

else

{

<false clause>

}

}

The else binds to the second if statement. The first if statement only has a true clause which contains the second if statement. The second if statement has a true clause and also a false clause.

if (<cond. exp. 1>)

{

if (<cond. exp. 2>)

{

<true clause>

}

}

else

{

<false clause>

}

The else binds to the first if statement. The first if statement has a true clause and a false clause. The second if statement has only a true clause and is within the true clause of the first if statement.

Figure 7-6 Nested if statements without indentation.

if (<cond. exp. 1>)

 

if (<cond. exp. 1>)

{

 

{

if (<cond. exp. 2>)

 

if (<cond. exp. 2>)

{

 

{

<true clause>

 

<true clause>

}

 

}

else

 

}

{

 

else

<false clause>

 

{

}

 

<false clause>

}

 

}

 

 

 

Figure 7-7 Indented if statements.

7 DRIVING LEDS 155

The use of an if statement is shown in the following fragment of code:

int Number;

cout << “Enter an integer Number “; cin >> Number;

if(Number > 50)

cout << “Number is greater than 50” << endl;

else

cout << “Number is less than or equal to 50” << endl;

The number entered by the user will be tested by the if statement and a message will be printed on the screen displaying the result of the test.

A compact version of the if statement can be implemented using the so-called conditional operator (?:). For example, by checking a variable named Switch, ON/OFF status of the switch can be printed on the screen using:

Switch == 1 ? cout << “on” : cout “off”;

This statement is equivalent to:

if(Switch == 1) cout << “on”;

else

cout << “off”;

7.3.2 The break and continue Statements

The break and continue statements are two important statements that can be used efficiently to enhance the functionality of our programs. Of the two statements, the break statement is more widely used. Their syntax is very simple and always used as follows:

break;

continue;

The break statement is used to terminate the execution of a loop (such as while, do-while, or for) or a switch statement. The continue statement is used to skip and continue the execution of loops. Figure 7-8 shows the two cases.

As mentioned previously, iterative loops can be nested; i.e. one loop within another. Similarly, a switch statement can be placed within a loop. In such situations, the break statement will be associated with the nearest loop or switch statement. The continue statement will be associated with the nearest loop and cannot be used with the switch statement.

The C++ language also supports the use of goto to jump to a label. Use of goto can severely damage the structure of a program. Its use is discouraged and is not explained in this text - see references listed in Section 7.11.

156 7 DRIVING LEDS

int i = 0, Sum = int n = 50;

Always true

while(1)

{

i++;

Sum += i; if(i==n) break;

}

0;

Infinite while loop

When i is equal to n, the if statement will execute break, terminating the infinite while loop.

int Sum = 0;

int n = 20, m = 30;

for(i=0; i<100; i++)

{

if((i>=n) && (i<=m)) continue;

Sum += i;

}

For all values of i between n and m, continue will be executed, forcing all remaining statements within the body of the for loop to be skipped. The next statement to be executed is the incremental expression i++.

Figure 7-8 The break and continue statements.

7.3.3 The switch case Statement

A switch-case statement is used to select and then execute one of several cases. Selection is carried out by a switch expression located after the keyword switch and enclosed between parenthesis.

The switch expression must produce an integer result.

switch(switch expression)

The body of the switch { statement starts here.

These two must be constant integer expressions such as 3, or 0x0C, etc.

The body of the switch } statement ends here.

case n1 : statements break;

case n2 : statements break;

.

.

.

default : statements

If the switch expression evaluates to n1, these statements will be executed.

If the switch expression evaluates to n2, these statements will be executed.

If the switch expression evaluates to none of the cases listed, the default case will be executed. The default case may be omitted.

Figure 7-9 The switch statement.

7 DRIVING LEDS 157

The switch expression must be of integral type such as char, unsigned char, int, unsigned int, etc. Program control will be transferred to a case statement that matches the value of the switch expression.

The cases are listed within the body of the switch statement. Immediately after the keyword case, there must be a constant integer expression, which must have a unique value. Each case may have any statement including an empty statement. All statements under a case will be executed sequentially.

The break statement must be used to exit a switch statement at the end of a particular case. If break is not used, program execution will flow on to the next case. Optionally, a special case named default may be used to take necessary action if no matching case is found.

Constant Integer Expression

A constant integer expression must produce an integer result and cannot contain

any variables.

#define TWIN 2

Here the symbolic constant TWIN is defined to be a substitute for the number 2.

 

Then

TWIN+1 is a constant integer expression. Note that TWIN is not a

 

 

variable.

 

 

 

 

 

 

 

However, if

int a=0;

 

 

Then

a+1

is not a constant integer expression, because a is a variable.

 

 

 

 

 

 

7.4 Arrays

An array is a collection of objects of the same type. The objects could be fundamental data types or user-defined data types. Each individual object of the collection is referred to as an element. Towards the end of the chapter, we will be using arrays to store LED lighting patterns for the program.

Arrays can be represented in different configurations or number of dimensions as shown in Figure 7-10. Each cell can store one object of the designated type. There is practically no limit to the number of dimensions an array can have.

The size of the array is given by the number of elements (cells) for each dimension. Using Figure 7-10 as an example, the sizes of the arrays are:

1-dimensional array: 5 elements.

2-dimensional array: 3 rows, 5 elements/row. Size = 15 elements.

3-dimensional array: 3 rows, 4 elements/row, 2 elements/row. Size = 24 elements.

158 7 DRIVING LEDS

 

 

 

 

 

 

 

 

 

 

 

 

1

 

 

 

0

1

2

3

4

0

1

2

3

4

 

0

 

 

 

 

 

 

 

 

0

 

 

 

 

 

0

 

0

1

2

3

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1 Dimensional

1

 

1

 

Array

2

 

2

 

 

 

 

 

 

 

 

 

 

 

 

 

2 Dimensional

 

3 Dimensional

 

 

Array

 

Array

Figure 7-10 Diagramatic representation of arrays.

Although the arrays can be represented as shown in Figure 7-10, in your computers memory the elements of the array are stored sequentially row after row, termed row-major fashion. In storing a 3-D array, the first layer is stored first in a rowmajor fashion and then the second layer in row-major fashion and so on.

One-Dimensional Arrays

When declaring one-dimensional arrays, the size of the array is specified within a pair of square brackets immediately after the array identifier. The array subscripts always start with 0 and range to the array size minus one. An example of a declaration is:

int a[10];

This declares an array of 10 int type objects. They are stored in adjacent memory locations starting from the element a[0] ranging up to a[9], making available a set of 10 elements as shown in Figure 7-11. Note that there is no element named a[10]. Attempting to access such an element will be illegal, since this memory location is not part of the array a.

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]

Figure 7-11 Schematic of a one-dimensional array.

If a variable subscript is used to access array elements, as in a[i], then i must be an integer expression and as just mentioned must not evaluate to a value outside the permitted range of array subscript values, in this case 0 to 9.

The array elements can be initialised individually during program execution by assigning each element a value. For example, the following code fragment sets the value of all elements to zero:

7 DRIVING LEDS 159

for(int i = 0; i < 10; i++) a[i] = 0;

Alternatively, the array elements can be initialised when the array is declared. The values for each element to be initialised need to be listed within braces and separated by commas as shown in the following line:

int a[8] = {2,3,7,4}; // 8 elements

In this example the array a is partially filled with the values listed between the braces; element a[0]=2, a[1]=3, a[2]=7, and a[3]=4. The remaining elements (a[4] to a[7]) that have not been explicitly initialised are initialised by default with values of zero. Therefore, to declare and initialise an array with all zero values can be done as follows:

int a[8] = {};

Accessing array elements

Individual elements of the array can be accessed by using a subscript. In the following example the array subscripts range from 0 to 7 (8 elements).

int

a[8];

//

declare

a

to be 8 elements

int

Result;

//

declare

a

variable named Result

a[0] = 2; // access and set a[0] to 2 a[1] = 3; // access and set a[1] to 3

Result = a[0]*a[1];

// 2*3 = 6

Two-Dimensional Arrays

A two dimensional array can be viewed as an array of one-dimensional arrays. Two-dimensional arrays have two sizes specified. The total number of elements is the product of the two sizes. For example, a two-dimensional array can be declared as follows:

number of rows

int b[2][5];

number of elements per row

Figure 7-12 Declaring a 2-D array.

Two subscripts are used to access each element of the array. In array b, one of the array dimensions ranges from 0 to 1 and the other dimension from 0 to 4. The array can be thought of as the arrangement shown in Figure 7-13. Note that elements are stored in consecutive memory locations in row-major fashion. That is, the first row

160 7 DRIVING LEDS

is stored first, immediately followed by the second row, and so forth. Thus, the element b[0][4] is immediately followed by the element b[1][0].

b[0][0]

b[0][1]

b[0][2]

b[0][3]

b[0][4]

 

 

 

 

 

b[1][0]

b[1][1]

b[1][2]

b[1][3]

b[1][4]

 

 

 

 

 

Figure 7-13 2-D array schematic representation.

The array elements can be individually initialised during program execution by assigning each element a value. For example, the following code fragment sets the values of all elements to zero.

int i, j;

for(i = 0; i < 2; i++) for(j = 0; j < 5; j++)

b[i][j] = 0;

Alternatively the array elements can be initialised when the array is declared. This is shown in the following line.

int b[2][5] = {{0,0,0,0,0};{0,0,0,0,0}};

Each row of initialised elements is enclosed by inner braces, and separated from adjacent rows by a semicolon.

7.5 Pointers

A pointer is an address of an entity that resides in memory. Examples of entities that reside in memory are; class objects, fundamental data type objects such as int, float, char, long, etc., arrays of objects (a group of objects of the same type), and functions. A pointer in C++ will hold where the object is and most of the time the pointer will know the type of object. For example, a pointer to an integer knows that the data type is integer and it will also know where the integer is, but it does not know the value of the integer.

Pointers play an important role in helping to make C++ programs very efficient. There are three major uses for pointers that offer distinct advantages: passing large objects to functions, dynamic memory allocation, and using virtual functions. In the most common case when passing a parameter to a function, we replace the parameter by a copy of the actual argument. If the actual argument is very large, the program will need to consume a large amount of memory when it creates a copy of the argument. It is more efficient to make a copy of where the large object

7 DRIVING LEDS 161

is than copy the entire object. This is done by using a pointer which occupies a small amount of memory in order to store the address of the object.

Dynamic memory allocation involves the provision of storage space at run-time. Normally, dynamic memory allocation is a need-based process – i.e. if during program operation there is a need for more memory it can be requested and will be granted depending on availability. The dynamic memory allocation process returns a pointer indicating the location in memory where the allocation has been made. This pointer can then be used to manipulate the data in the allocated memory area.

Perhaps the most obscure use of pointers is in association with virtual functions which will be described in detail in Chapter 8. The following sections describe general use of pointers in the C++ language.

Two unary operators are used closely with pointers. As mentioned before, a unary operator takes only one argument. These operators are given in Table 7-1.

Table 7-1 Unary operators used with pointers.

Operator Name

&address of operator

*indirection operator

The address of operator can be used to find the address of an object in memory.

The indirection operator can be used to obtain the contents of a location given its memory address. This is also known as de-referencing.

7.5.1 Declaration of Pointer Variables

As you know, there is a dedicated data type named int to represent integers and many other fundamental data types. Programmers can also create their own data types such as DAC created in Chapter 6. However, there is no unique data type named pointer. Since all memory addresses are integers, all pointer data types carry integer values. The locations pointed to by these addresses can contain all types of data or functions.

The asterisk identifies the identifier as a pointer variable

data type *identifier;

To be replaced by a data type such as int, char or an object class type such as DAC

Figure 7-14 Syntax of a pointer declaration.

162 7 DRIVING LEDS

When declaring a pointer variable, the C++ language requires us to specify the type of data or function pointed to by the pointer variable. We will see the significance of knowing the data type pointed to by the pointer variables when pointer arithmetic is explained in section 7.5.6. In the simplest of cases, the syntax for declaring pointer variables takes the form shown in Figure 7-14. Pointers to different entities are each declared differently as described ahead.

7.5.2 Pointers to Scalar Quantities

A single item is referred to as a scalar quantity. If a pointer variable is declared to point to one solitary integer, then that pointer is said to point to a scalar quantity. This is in contrast to pointers that point to arrays. Examples of declarations of ordinary variables and declaration of pointers to scalar quantities are shown in Table 7-2.

Table 7-2 Declaration of scalar identifiers and pointers to scalar identifiers.

Declaration – scalar identifiers

Declaration – pointers to scalar identifiers

int a;

int a;

 

 

 

int *IntPtr = &a;

int b = 0;

int b

=

0;

 

*IntPtr

= b;

float p = 0.0;

float

p

= 0.0;

 

float

*FltPtr = &p

The following line is a combined declaration and initialisation of a pointer variable to an int:

int *IntPtr = &a;

Declaration part

int *IntPtr = &a;

Initialisation part

The same effect can be achieved with the following two lines:

int *IntPtr; IntPtr = &a;

7 DRIVING LEDS 163

The first statement declares a pointer to an int. The second statement uses the ‘address of’ operator ‘&’ to obtain the address of the integer variable a which is assigned to the pointer variable IntPtr. Note that the int type variable a must be declared before assigning its address to IntPtr.

The statement:

*IntPtr = b;

carries out a de-referencing and an assignment operation. The expression *IntPtr reads as ‘the contents of the location pointed to by IntPtr’. This is known as de-referencing. Therefore, the entire expression reads as ‘the contents of the location pointed to by IntPtr is assigned the value of b’. Since IntPtr already points to the location of a, the effect is same as:

a = b;

An example of declaring a pointer to a float type variable and assigning it a value is given in Table 7-2.

NOTE

Given the following two declarations;

int a=0;

float* FltPtr;

An assignment of the form;

FltPtr = &a; // Illegal!

is illegal. The pointer FltPtr is expected to carry an address of a float type

object. However, &a is an address of an integer object. These two do not match

and therefore it is an illegal assignment.

7.5.3 Pointers to Class Objects

Pointers to class objects are declared in a similar manner to pointers to scalar quantities. An example is given below:

ParallelPort *PortPtr;

Here the data type is ParallelPort and the pointer variable is PortPtr. A pointer to an object of the DAC class can be declared as follows:

DAC *DACPtr;

An object of type DAC can be declared as follows:

DAC Dac;