Let’s look at the implications of Listing 7.5. The function call sum_arr(cookies, ArSize)
passes the address of the first element of the cookies
array and the number of elements of the array to the sum_arr()
function. The sum_arr()
function initializes the cookies
address to the pointer variable arr
and initializes ArSize
to the int
variable n
. This means Listing 7.5 doesn’t really pass the array contents to the function. Instead, it tells the function where the array is (the address), what kind of elements it has (the type), and how many elements it has (the n
variable). (See Figure 7.4.) Armed with this information, the function then uses the original array. If you pass an ordinary variable, the function works with a copy. But if you pass an array, the function works with the original. Actually, this difference doesn’t violate C++’s pass-by-value approach. The sum_arr()
function still passes a value that’s assigned to a new variable. But that value is a single address, not the contents of an array.
Is the correspondence between array names and pointers a good thing? Indeed, it is. The design decision to use array addresses as arguments saves the time and memory needed to copy an entire array. The overhead for using copies can be prohibitive if you’re working with large arrays. With copies, not only does a program need more computer memory, but it has to spend time copying large blocks of data. On the other hand, working with the original data raises the possibility of inadvertent data corruption. That’s a real problem in classic C, but ANSI C and C++’s const
modifier provides a remedy. You’ll soon see an example. But first, let’s alter Listing 7.5 to illustrate some points about how array functions operate. Listing 7.6 demonstrates that cookies
and arr
have the same value. It also shows how the pointer concept makes the sum_arr
function more versatile than it may have appeared at first. To provide a bit of variety and to show you what it looks like, the program uses the std::
qualifier instead of the using
directive to provide access to cout
and endl
.
// arrfun2.cpp -- functions with an array argument
#include <iostream>
const int ArSize = 8;
int sum_arr(int arr[], int n);
// use std:: instead of using directive
int main()
{
int cookies[ArSize] = {1,2,4,8,16,32,64,128};
// some systems require preceding int with static to
// enable array initialization
std::cout << cookies << " = array address, ";
// some systems require a type cast: unsigned (cookies)
std::cout << sizeof cookies << " = sizeof cookies
";
int sum = sum_arr(cookies, ArSize);
std::cout << "Total cookies eaten: " << sum << std::endl;
sum = sum_arr(cookies, 3); // a lie
std::cout << "First three eaters ate " << sum << " cookies.
";
sum = sum_arr(cookies + 4, 4); // another lie
std::cout << "Last four eaters ate " << sum << " cookies.
";
return 0;
}
// return the sum of an integer array
int sum_arr(int arr[], int n)
{
int total = 0;
std::cout << arr << " = arr, ";
// some systems require a type cast: unsigned (arr)
std::cout << sizeof arr << " = sizeof arr
";
for (int i = 0; i < n; i++)
total = total + arr[i];
return total;
}
Here’s the output of the program in Listing 7.6:
003EF9FC = array address, 32 = sizeof cookies
003EF9FC = arr, 4 = sizeof arr
Total cookies eaten: 255
003EF9FC = arr, 4 = sizeof arr
First three eaters ate 7 cookies.
003EFA0C = arr, 4 = sizeof arr
Last four eaters ate 240 cookies.
Note that the address values and the array and integer sizes will vary from system to system. Also some implementations will display the addresses in base 10 notation instead of in hexadecimal. Others will use hexadecimal digits and the 0x
hexadecimal prefix.
Listing 7.6 illustrates some very interesting points about array functions. First, note that cookies
and arr
both evaluate to the same address, exactly as claimed. But sizeof cookies
is 32
, whereas sizeof arr
is only 4
. That’s because sizeof cookies
is the size of the whole array, whereas sizeof arr
is the size of the pointer variable. (This program execution takes place on a system that uses 4-byte addresses.) By the way, this is why you have to explicitly pass the size of the array rather than use sizeof arr
in sum_arr()
; the pointer by itself doesn’t reveal the size of the array.
Because the only way sum_arr()
knows the number of elements in the array is through what you tell it with the second argument, you can lie to the function. For example, the second time the program uses the function, it makes this call:
sum = sum_arr(cookies, 3);
By telling the function that cookies
has just three elements, you get the function to calculate the sum of the first three elements.
Why stop there? You can also lie about where the array starts:
sum = sum_arr(cookies + 4, 4);
Because cookies
acts as the address of the first element, cookies + 4
acts as the address of the fifth element. This statement sums the fifth, sixth, seventh, and eighth elements of the array. Note in the output how the third call to the function assigns a different address to arr
than the first two calls did. And yes, you can use &cookies[4]
instead of cookies + 4
as the argument; they both mean the same thing.
To indicate the kind of array and the number of elements to an array-processing function, you pass the information as two separate arguments:
void fillArray(int arr[], int size); // prototype
Don’t try to pass the array size by using brackets notation:
void fillArray(int arr[size]); // NO -- bad prototype
3.138.37.20