• No results found

Pointers and Dynamic Arrays

4.2 POINTERS AND ARRAYS AS PARAMETERS

A function parameter may be a pointer or an array—but some care is needed to ensure that the connection between the argument and the formal parameter is the intended connection. We’ll look at several common situations.

Value parameters that are pointers. Figure 4.3 shows a silly function to illustrate a value parameter that is a pointer. The function’s prototype is:

void make_it_42( );

The prototype indicates that the parameter i_ptr has type int*, that is, a pointer to an integer. The parameter is a value parameter because the reference symbol& does not appear. Within the parameter list, many programmers place

A Function Implementation

// Precondition: i_ptr is pointing to an integer variable.

// Postcondition: The integer that i_ptr is pointing at has been changed to 42.

{

*i_ptr = 42;

}

FIGURE 4.3 A Value Parameter That Is a Pointer

void make_it_42(int* i_ptr)

int* i_ptr many

programmers place the * with the data type

Pointers and Arrays as Parameters 167

the asterisk with the data type (int) rather than with the parameter name (i_ptr)—although the compiler will accept the asterisk in either position. The reason for the placement with the data type is to emphasize that the “complete type” of the parameter is “an integer pointer.”

The only purpose of make_it_42 is to show what happens when a value parameter is a pointer. Notice that the body of the function does not actually changei_ptr; it changes only the integer that i_ptr points to. Let’s examine a program that calls make_it_42. The program declares a pointer to an integer, allocating memory for the pointer to point to, and calls make_it_42:

int *main_ptr;

main_ptr = new int;

make_it_42(main_ptr);

As with any value parameter, the actual argument provides the initial value for the formal parameter. In the example, main_ptr provides the initial value for the formal parameter i_ptr of the make_it_42 function. This means that the parameteri_ptr will point to the same place that main_ptr is already pointing to. At the start of the function’s execution, we have this situation:

Within the make_it_42 function, we have the assignment . The assignment places 42 in the location that i_ptr points to, as shown here:

Now main_ptr is pointing to a newly allocated integer.

main_ptr

a new integer Next, we call make_it_42, with

main_ptr as the actual parameter.

i_ptr main_ptr

a new integer The argument, main_ptr,

provides the initial value for the parameter i_ptr.

*i_ptr = 42

i_ptr main_ptr

a new integer In the body of make_it_42, 42

the assignment statement

*i_ptr = 42

places 42 in the location that i_ptr points to.

Finally, the function returns and the formal parameter i_ptr is no longer avail-able. However, the pointer variable main_ptr is still around, and it is still point-ing to the same location. But the location has a new value of 42, as shown here:

In ordinary C programming (rather than C++), pointers are frequently used as value parameters. This is because C did not originally have reference parameters, so the only convenient way for a function to affect its actual arguments is with a value parameter that is a pointer.

Array parameters. There is a surprising twist when a parameter is an array.

The parameter is automatically treated as a pointer that points to the first ele-ment of the array. Within the body of the function, the pointer can be used with array notation, which is just like any other pointer that points to the first element of an array. For example, Figure 4.4 shows a function to set the first n elements of an array to the number 42.

a surprising twist for array parameters

Notice that the array parameter is indicated by placing brackets after the parameter name so the function’s prototype is:

void make_it_all_42( , size_t n);

The size of the array is not needed inside the brackets, but usually there is another parameter (such as size_t n) that indicates the size of the array.

If the body of the function changes the components of the array, the changes do affect the actual argument. The reason that the argument is affected is that an

Value Parameters That Are Pointers

When a value parameter is a pointer, the function may change the value in the location that the pointer points to.

The actual argument in the calling program will still point to the same location, but that location will have a new value.

Syntax in the parameter list:

Type_Name* var_name

Example from Figure 4.3 on page 166,

void make_it_42( );

main_ptr

a new integer The original argument,

main_ptr, is pointing to 42 the same location, but the location has a new value.

int* i_ptr

double data[ ]

Pointers and Arrays as Parameters 169

array parameter is actually a pointer to the first element of the array. Here is an example that calls the function from Figure 4.4:

double main_array[10];

make_it_all_42(main_array, 10);

cout << main_array[5];

The actual argument of make_it_all_42 may be a dynamic array, as shown here:

double *numbers;

numbers = new double[10];

make_it_all_42(numbers, 10);

Array Parameters

A parameter that is an array is indicated by placing [ ] after the parameter name, as shown here:

Syntax in the parameter list:

Type_Name var_name[ ] Example from Figure 4.4:

void make_it_all_42( , size_t n);

There is usually a separate size_t parameter to indicate the size of the array. Any changes that the function makes to the components of the array do affect the actual argument.

Set all 10 array components to 42.

This prints 42.

Allocate a dynamic array.

Set all elements to 42.

A Function Implementation

// Precondition: data is an array with at least n components.

// Postcondition: The first n elements of the array data have been set to 42.

// Library facilities used: cstdlib {

size_t i;

for (i = 0; i < n; ++i) data[i] = 42;

}

FIGURE 4.4 An Array Parameter

void make_it_all_42(double data[ ], size_t n) double data[ ]

Const parameters that are pointers or arrays. A parameter that is a pointer or an array may also include the const keyword, as in these two prototypes:

bool is_42( int* i_ptr);

double average( double data[ ], size_t n);

Theconst keyword in the first prototype indicates that i_ptr is a pointer to a constant integer. In other words, the implementation of is_42 may examine

*i_ptr, but may not change the value of *i_ptr. The complete body of is_42 is shown in Figure 4.5, where *i_ptr is compared to the number 42.

The second prototype indicates that data is an array and, because of the const

keyword, the function cannot change the array entries. The average function may examine all the array entries, but it may not change them. Our intention is foraverage to return the arithmetic average of all the entries in the data array, as shown in the second half of Figure 4.5.

const const

A Function Implementation

// Precondition: i_ptr is pointing to an integer variable.

// Postcondition: The return value is true if *i_ptr is 42.

{

return (*i_ptr == 42);

}

// Library facilities used: cassert, cstdlib {

size_t i; // An array index

double sum; // The sum of data[0] through data[n - 1]

assert(n > 0);

// Add up the n numbers and return the average.

sum = 0;

for (i = 0; i < n; ++i) sum += data[i];

return (sum/n);

}

FIGURE 4.5 A Const Parameter That Is a Pointer or Array

bool is_42(const int* i_ptr)

double average(const double data[ ], size_t n)

Pointers and Arrays as Parameters 171

Reference parameters that are pointers. Sometimes a function will actually change a pointer parameter so that the pointer points to a new location, and the programmer needs the change to affect the actual argument. This is the only sit-uation where a reference parameter will be a pointer. For example, Figure 4.6 shows a function named allocate_doubles that allocates memory for a new dynamic array. Here is the function’s prototype:

void allocate_doubles( , size_t& n);

The parameter p is a pointer to a double (that is,double*) and it is a reference parameter (indicated by the symbol &). The complete parameter type is thus

double*&.

In the implementation of allocate_doubles, the parameter p is changed so that it points to a newly allocated array. In a program, we can use

allocate_doubles to allocate an array of double values, with the size of the array determined by interacting with the user. Here is an example that calls

allocate_doubles:

double *numbers;

size_t array_size;

allocate_doubles(numbers, array_size);

In this example, the allocate_doubles function asks the user how many

double numbers should be allocated. The user’s answer is used to set the CLARIFYING THE CONST KEYWORD

Part 6: Const Parameters That Are Pointers or Arrays A parameter that is a pointer or array

may include the const keyword, as shown here:

Syntax in the parameter list:

const Type_Name* var_name const Type_Name var_name[ ]

Examples from Figure 4.5:

bool is_42( int* i_ptr);

double average( double data[ ], ...

The functions may examine the item that is pointed to (or the array), but changing the item (or array) is forbidden.

1. DECLARED CONSTANTS:PAGE12

2. CONSTANT MEMBER FUNCTIONS:PAGE38

3. CONST REFERENCE PARAMETERS:PAGE72

4. STATIC MEMBER CONSTANTS:PAGE104

5. CONST ITERATORS: PAGE 144

6. CONST PARAMETERS THAT ARE POINTERS OR ARRAYS

7. THE CONST KEYWORD WITH A POINTER TO A NODE, AND THE NEED FOR TWO VERSIONS OF SOME MEMBER FUNCTIONS: PAGE 227

const const

double*& p

argument, array_size. The function then allocates an array of the requested size, and the argument called numbers is set to point to the first component of the array. Because the function makes its formal parameter p point to a newly allocated array of double numbers, and we want the actual argument numbers to point to the newly allocated memory, we are required to use a reference parameter.

If you have defined a type definition for a pointer type, then you can avoid the cumbersome syntax of *&. For example, if double_ptr has been defined to be a pointer to a double number, then we could write this prototype:

void allocate_doubles( , size_t& n);

Reference Parameters That Are Pointers Sometimes a function will actually change a pointer parameter so that the pointer points to a new location, and the programmer needs the change to affect the actual parameter. This is the only situation in which a reference parameter will be a pointer.

Syntax in the parameter list:

Type_Name*& var_name Example from Figure 4.6:

void allocate_doubles( ,size_t& n);

A Function Implementation

// Postcondition: The user has been prompted for a size n, and this size has been read.

// The pointer p has been set to point to a new dynamic array containing n doubles.

// NOTE: If there is insufficient dynamic memory, then bad_alloc is thrown.

// Library facilities used: iostream, cstdlib {

cout << "How many doubles should I allocate?" << endl;

cout << "Please type a positive integer answer: ";

cin >> n;

p = new double[n];

}

FIGURE 4.6 A Reference Parameter That Is a Pointer

void allocate_doubles(double*& p, size_t& n)

Allocate the array of n doubles.

double_ptr& p

double*& p