The Implications of Using Arrays as Arguments

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.

Figure 7.4. Telling a function about an array.

Image

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.

Listing 7.6. arrfun2.cpp


// 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.

Program Notes

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.


Note

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


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.37.20