}

        else if (temp < 0)     // signal to terminate

            break;

        ar[i] = temp;

    }

    return i;

}

// the following function can use, but not alter,

// the array whose address is ar

void show_array(const double ar[], int n)

{

    using namespace std;

    for (int i = 0; i < n; i++)

    {

        cout << "Property #" << (i + 1) << ": $";

        cout << ar[i] << endl;

    }

}

// multiplies each element of ar[] by r

void revalue(double r, double ar[], int n)

{

    for (int i = 0; i < n; i++)

        ar[i] *= r;

}

Here are two sample runs of the program in Listing 7.7:

Enter value #1: 100000

Enter value #2: 80000

Enter value #3: 222000

Enter value #4: 240000

Enter value #5: 118000

Property #1: $100000

Property #2: $80000

Property #3: $222000

Property #4: $240000

Property #5: $118000

Enter revaluation factor: 0.8

Property #1: $80000

Property #2: $64000

Property #3: $177600

Property #4: $192000

Property #5: $94400

Done.

Enter value #1: 200000

Enter value #2: 84000

Enter value #3: 160000

Enter value #4: -2

Property #1: $200000

Property #2: $84000

Property #3: $160000

Enter reevaluation factor: 1.20

Property #1: $240000

Property #2: $100800

Property #3: $192000

Done.

Recall that fill_array() prescribes that input should quit when the user enters five properties or enters a negative number, whichever comes first. The first output example illustrates reaching the five-property limit, and the second output example illustrates that entering a negative value terminates the input phase.

Program Notes

We’ve already discussed the important programming details related to the real estate example, so let’s reflect on the process. You began by thinking about the data type and designed appropriate functions to handle the data. Then you assembled these functions into a program. This is sometimes called bottom-up programming because the design process moves from the component parts to the whole. This approach is well suited to OOP, which concentrates on data representation and manipulation first. Traditional procedural programming, on the other hand, leans toward top-down programming, in which you develop a modular grand design first and then turn your attention to the details. Both methods are useful, and both lead to modular programs.

The Usual Array Function Idiom

Suppose you want a function to process an array, say, of type double values. If the function is intended to modify the array, the prototype might look like this:

void f_modify(double ar[], int n);

If the function preserves values, the prototype might look like this:

void _f_no_change(const double ar[], int n);

Of course, you can omit the variable names in the prototypes, and the return type might be something other than void. The main points are that ar really is a pointer to the first element of the passed array and that because the number of elements is passed as an argument, either function can be used with any size of array as long as it is an array of double:

double rewards[1000];

double faults[50];

...

f_modify(rewards, 1000);

f_modify(faults, 50);

This idiom (pass the array name and size as arguments) works by passing two numbers—the array address and the number of elements. As you have seen, the function loses some knowledge about the original array; for example, it can’t use sizeof to get the size and relies on you to pass the correct number of elements.

Functions Using Array Ranges

As you’ve seen, C++ functions that process arrays need to be informed about the kind of data in the array, the location of the beginning of the array, and the number of elements in the array. The traditional C/C++ approach to functions that process arrays is to pass a pointer to the start of the array as one argument and to pass the size of the array as a second argument. (The pointer tells the function both where to find the array and the kind of data in it.) That gives the function the information it needs to find all the data.

There is another approach to giving a function the information it needs: specify a range of elements. This can be done by passing two pointers—one identifying the start of the array and one identifying the end of the array. The C++ Standard Template Library (STL; presented in Chapter 16, “The string Class and the Standard Template Library”), for example, generalizes the range approach. The STL approach uses the concept of “one past the end” to indicate an extent. That is, in the case of an array, the argument identifying the end of the array would be a pointer to the location just after the last element. For example, suppose you have this declaration:

double elbuod[20];

Перейти на страницу:

Все книги серии Developer's Library

Похожие книги