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 will see that the size of a vector is built inevery 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 referencethe 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.3
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 22)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 size of the array is not required between the array brackets. If it is included, the compiler ignores it. Because C++ passes arrays to functions by reference, when the called function uses the array name b, it will in fact be referring 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 learned 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 2223 print the five original elements of integer array a. Line 28 passes a and its size to function modifyArray (lines 4550), which multiplies each of a's elements by 2 (through parameter b). Then, lines 3233 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 5458), 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.
Figure 7.14. Passing arrays and individual array elements to functions.
(This item is displayed on pages 348 - 349 in the print version)
1 // Fig. 7.14: fig07_14.cpp 2 // Passing arrays and individual array elements to functions. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include 8 using std::setw; 9 10 void modifyArray( int [], int ); // appears strange 11 void modifyElement( int ); 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 << " The values of the original array are: "; 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: "; 30 31 // output modified array elements 32 for ( int j = 0; j < arraySize; j++ ) 33 cout << setw( 3 ) << a[ j ]; 34 35 cout << " Effects of passing array element by value:" 36 << " a[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
|
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 the programmer to prevent accidental modification of array elements in the function's body.
Figure 7.15 demonstrates the const qualifier. Function tryToModifyArray (lines 2126) 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 2325) results in a compilation error. The Microsoft Visual C++.NET compiler, for example, produces the error "l-value specifies 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 erroryou 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.
Figure 7.15. const type qualifier applied to an array parameter.
(This item is displayed on page 350 in the print version)
1 // Fig. 7.15: fig07_15.cpp 2 // Demonstrating the const type qualifier. 3 #include 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 ] << ' '; 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; // error 24 b[ 1 ] /= 2; // error 25 b[ 2 ] /= 2; // error 26 } // end function tryToModifyArray Borland C++ command-line compiler error message:
Microsoft Visual C++ .NET compiler error message:
GNU C++ compiler error message:
|
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. |
Introduction to Computers, the Internet and World Wide Web
Introduction to C++ Programming
Introduction to Classes and Objects
Control Statements: Part 1
Control Statements: Part 2
Functions and an Introduction to Recursion
Arrays and Vectors
Pointers and Pointer-Based Strings
Classes: A Deeper Look, Part 1
Classes: A Deeper Look, Part 2
Operator Overloading; String and Array Objects
Object-Oriented Programming: Inheritance
Object-Oriented Programming: Polymorphism
Templates
Stream Input/Output
Exception Handling
File Processing
Class string and String Stream Processing
Web Programming
Searching and Sorting
Data Structures
Bits, Characters, C-Strings and structs
Standard Template Library (STL)
Other Topics
Appendix A. Operator Precedence and Associativity Chart
Appendix B. ASCII Character Set
Appendix C. Fundamental Types
Appendix D. Number Systems
Appendix E. C Legacy Code Topics
Appendix F. Preprocessor
Appendix G. ATM Case Study Code
Appendix H. UML 2: Additional Diagram Types
Appendix I. C++ Internet and Web Resources
Appendix J. Introduction to XHTML
Appendix K. XHTML Special Characters
Appendix L. Using the Visual Studio .NET Debugger
Appendix M. Using the GNU C++ Debugger
Bibliography