7.5. Passing Arrays to Functions
To pass an array argument to a function,
specify the name of the array without any brackets. For example, if array
hourlyTemperatures has been declared as
int hourlyTemperatures[ 24 ];
the function call
modifyArray( hourlyTemperatures, 24 );
passes array hourlyTemperatures and its size to function modifyArray. When passing an array to a function, the array size is
normally passed as well, so the function can process the specific number of
elements in the array. Otherwise, we would need to build this knowledge into the
called function itself or, worse yet, place the array size in a global variable.
In Section
7.11, when we present C++ Standard Library class
template vector to represent a more robust
type of array, you'll see that the size of a vector is built in—every
vector object "knows" its own size, which can be obtained by invoking
the vector object's size member function. Thus, when we pass a
vector object into
a function, we will not have to pass the size of the vector as an
argument.
C++ passes arrays to functions by
reference—the called functions can modify the element values in the callers'
original arrays. The value of the name of the array is the address in the
computer's memory of the first element of the array. Because the starting
address of the array is passed, the called function knows precisely where the
array is stored in memory. Therefore, when the called function modifies array
elements in its function body, it is modifying the actual elements of the array
in their original memory locations.
Performance Tip 7.2
|
Passing
arrays by reference makes sense for performance reasons. If arrays were passed
by value, a copy of each element would be passed. For large, frequently passed
arrays, this would be time consuming and would require considerable storage for
the copies of the array
elements. |
Software Engineering Observation 7.3
|
It is possible
to pass an array by value (by using a simple trick we explain in Chapter
19)—however, this is rarely
done. |
Although entire arrays are passed by
reference, individual array elements are passed by value exactly as simple
variables are. Such simple single pieces of data are called scalars or scalar
quantities. To pass an element of an array to a
function, use the subscripted name of the array element as an argument in the
function call. In Chapter
6, we showed how to pass scalars (i.e., individual
variables and array elements) by reference with references. In Chapter
8, we show how to pass scalars by reference with
pointers.
For a function to receive an array
through a function call, the function's parameter list must specify that the
function expects to receive an array. For example, the function header for
function modifyArray might be written as
void modifyArray( int b[], int arraySize )
indicating that modifyArray
expects to receive the address of an array of integers in parameter b and the number of array elements in parameter
arraySize. The array's size is not required
in the array brackets. If it is included, the compiler ignores it; thus, arrays
of any size can be passed to the function. C++ passes arrays to functions by
reference—when the called function uses the array name b, it refers to the actual array in the caller (i.e., array
hourlyTemperatures discussed at the
beginning of this section).
Note the strange appearance of the
function prototype for modifyArray
void modifyArray( int [], int );
This prototype could have been written
void modifyArray( int anyArrayName[], int anyVariableName );
but, as we saw in Chapter
3, C++ compilers ignore variable names in
prototypes. Remember, the prototype tells the compiler the number of arguments
and the type of each argument (in the order in which the arguments are expected
to appear).
The program in Fig. 7.14
demonstrates the difference between passing an entire array and passing an array
element. Lines 22–23 print the five original elements of integer array
a. Line 28 passes a and its size to
function modifyArray (lines 45–50), which multiplies each of
a's elements by 2 (through parameter b). Then, lines 32–33
print array a again in main. As the output shows, the elements
of a are indeed modified by modifyArray. Next, line 36 prints
the value of scalar a[3], then line 38 passes element a[ 3 ]
to function modifyElement (lines 54–58), which
multiplies its parameter by 2 and prints the new value. Note that when line 39
again prints a[3] in main, the value has not been modified, because individual array
elements are passed by value.
Fig. 7.14. Passing arrays
and individual array elements to functions.
1 // Fig. 7.14: fig07_14.cpp
2 // Passing arrays and individual array elements to functions.
3 #include <iostream>
4 using std::cout;
5 using std::endl;
6
7 #include <iomanip>
8 using std::setw;
9
10 void modifyArray( int [], int ); // appears strange; array and size
11 void modifyElement( int ); // receive array element value
12
13 int main()
14 {
15 const int arraySize = 5; // size of array a
16 int a[ arraySize ] = { 0, 1, 2, 3, 4 }; // initialize array a
17
18 cout << "Effects of passing entire array by reference:"
19 << "\n\nThe values of the original array are:\n";
20
21 // output original array elements
22 for ( int i = 0; i < arraySize; i++ )
23 cout << setw( 3 ) << a[ i ];
24
25 cout << endl;
26
27 // pass array a to modifyArray by reference
28 modifyArray( a, arraySize );
29 cout << "The values of the modified array are:\n";
30
31 // output modified array elements
32 for ( int j = 0; j < arraySize; j++ )
33 cout << setw( 3 ) << a[ j ];
34
35 cout << "\n\n\nEffects of passing array element by value:"
36 << "\n\na[3] before modifyElement: " << a[ 3 ] << endl;
37
38 modifyElement( a[ 3 ] ); // pass array element a[ 3 ] by value
39 cout << "a[3] after modifyElement: " << a[ 3 ] << endl;
40
41 return 0; // indicates successful termination
42 } // end main
43
44 // in function modifyArray, "b" points to the original array "a" in memory
45 void modifyArray( int b[], int sizeOfArray )
46 {
47 // multiply each array element by 2
48 for ( int k = 0; k < sizeOfArray; k++ )
49 b[ k ] *= 2;
50 } // end function modifyArray
51
52 // in function modifyElement, "e" is a local copy of
53 // array element a[ 3 ] passed from main
54 void modifyElement( int e )
55 {
56 // multiply parameter by 2
57 cout << "Value of element in modifyElement: " << ( e *= 2 ) << endl;
58 } // end function modifyElement
|
Effects of passing entire array by reference:
The values of the original array are:
0 1 2 3 4
The values of the modified array are:
0 2 4 6 8
Effects of passing array element by value:
a[3] before modifyElement: 6
Value of element in modifyElement: 12
a[3] after modifyElement: 6
|
There may be
situations in your programs in which a function should not be allowed to modify
array elements. C++ provides the type qualifier const that can be used to prevent modification of array values in
the caller by code in a called function. When a function specifies an array
parameter that is preceded by the const
qualifier, the elements of the array become constant in the function body, and
any attempt to modify an element of the array in the function body results in a
compilation error. This enables you to prevent accidental modification of array
elements in the function's body.
Figure
7.15 demonstrates the const qualifier. Function
tryToModifyArray (lines 21–26) is defined with parameter const int
b[], which specifies that array b is
constant and cannot be modified. Each of the three attempts by the function to
modify array b's elements (lines 23–25)
results in a compilation error. The Borland C++ compiler, for example, produces
the error "Cannot modify a const object." [Note: The C++ standard defines
an "object" as any "region of storage," thus including variables or array
elements of fundamental data types as well as instances of
classes (what we've been calling objects).] This message indicates that using a
const object (e.g., b[0]) as an lvalue is an error—you cannot
assign a new value to a const object by placing it
on the left of an assignment operator. Note that compiler error messages vary
between compilers (as shown in Fig. 7.15). The const qualifier will be discussed again in Chapter
10.
Fig. 7.15. const type
qualifier applied to an array parameter.
1 // Fig. 7.15: fig07_15.cpp
2 // Demonstrating the const type qualifier.
3 #include <iostream>
4 using std::cout;
5 using std::endl;
6
7 void tryToModifyArray( const int [] ); // function prototype
8
9 int main()
10 {
11 int a[] = { 10, 20, 30 };
12
13 tryToModifyArray( a );
14 cout << a[ 0 ] << ' ' << a[ 1 ] << ' ' << a[ 2 ] << '\n';
15
16 return 0; // indicates successful termination
17 } // end main
18
19 // In function tryToModifyArray, "b" cannot be used
20 // to modify the original array "a" in main.
21 void tryToModifyArray( const int b[] )
22 {
23 b[ 0 ] /= 2; // compilation error
24 b[ 1 ] /= 2; // compilation error
25 b[ 2 ] /= 2; // compilation error
26 } // end function tryToModifyArray
|
| Borland C++ command-line compiler
error message: |
Error E2024 fig07_15.cpp 23: Cannot modify a const object
in function tryToModifyArray(const int * const)
Error E2024 fig07_15.cpp 24: Cannot modify a const object
in function tryToModifyArray(const int * const)
Error E2024 fig07_15.cpp 25: Cannot modify a const object
in function tryToModifyArray(const int * const)
|
| Microsoft Visual C++ compiler
error message: |
c:\cppfp_examples\ch07\fig07_15\fig07_15.cpp(23) : error C3892: 'b' : you
cannot assign to a variable that is const
c:\cppfp_examples\ch07\fig07_15\fig07_15.cpp(24) : error C3892: 'b' : you
cannot assign to a variable that is const
c:\cppfp_examples\ch07\fig07_15\fig07_15.cpp(25) : error C3892: 'b' : you
cannot assign to a variable that is const
|
| GNU C++ compiler error
message: |
fig07_15.cpp:23: error: assignment of read-only location
fig07_15.cpp:24: error: assignment of read-only location
fig07_15.cpp:25: error: assignment of read-only location
|
Common Programming Error 7.11
|
Forgetting that
arrays in the caller are passed by reference, and hence can be modified in
called functions, may result in logic
errors. |
Software Engineering Observation 7.4
|
Applying the const type qualifier to an array parameter in a function
definition to prevent the original array from being modified in the function
body is another example of the principle of least privilege. Functions should
not be given the capability to modify an array unless it is absolutely
necessary. |