You can use both array indexed variables and entire arrays as arguments to functions. We first discuss array indexed variables as arguments to functions.
An indexed variable can be an argument to a function in exactly the same way that any variable can be an argument. For example, suppose a program contains the following declarations:
int
i, n, a[10];
If myFunction
takes one argument of type int
, then the following is legal:
myFunction(n);
Since an indexed variable of the array a
is also a variable of type int
, just like n
, the following is equally legal:
myFunction(a[3]);
There is one subtlety that does apply to indexed variables used as arguments. For example, consider the following function call:
myFunction(a[i]);
If the value of i
is 3
, then the argument is a[3]
. On the other hand, if the value of i
is 0
, then this call is equivalent to the following:
myFunction(a[0]);
The indexed expression is evaluated in order to determine exactly which indexed variable is given as the argument.
Display 7.3 contains an example of indexed variables used as function arguments. The program shown gives five additional vacation days to each of three employees in a small business. The program is extremely simple, but it does illustrate how indexed variables are used as arguments to functions. Notice the function adjustDays
. This function has a formal parameter called oldDays
that is of type int
. In the main body of the program, this function is called with the argument vacation[number]
for various values of number
. Notice that there was nothing special about the formal parameter oldDays
. It is just an ordinary formal parameter of type int
, which is the base type of the array vacation
. In Display 7.3 the indexed variables are call-by-value arguments. The same remarks apply to call-by-reference arguments. An indexed variable can be a call-by-value argument or a call-by-reference argument.
1
//Illustrates the use of an indexed variable as an argument.
2
//Adds 5 to each employee's allowed number of vacation days.
3 #include <iostream> 4
const int
NUMBER_OF_EMPLOYEES = 3; 5
int
adjustDays(
intoldDays); 6
//Returns oldDays plus 5.
7
int
main( ) 8 { 9
using namespace
std; 10
int
vacation[NUMBER_OF_EMPLOYEES], number; 11 cout << "Enter allowed vacation days for employees 1" 12 << " through " << NUMBER_OF_EMPLOYEES << ":\n"; 13
for
(number = 1; number <= NUMBER_OF_EMPLOYEES; number++) 14 cin >> vacation[number − 1]; 15
for
(number = 0; number < NUMBER_OF_EMPLOYEES; number++) 16 vacation[number] = adjustDays(vacation[number]); 17 cout << "The revised number of vacation days are:\n"; 18
for
(number = 1; number <= NUMBER_OF_EMPLOYEES; number++) 19 cout << "Employee number " << number 20 << " vacation days = " << vacation[number-1] << endl; 21
return0; 22 } 23
int
adjustDays(int
oldDays) 24 { 25
return
(oldDays + 5); 26 }
Sample Dialogue
Enter allowed vacation days for employees 1 through 3:
10 20 5The revised number of vacation days are: Employee number 1 vacation days = 15 Employee number 2 vacation days = 25 Employee number 3 vacation days = 10
Consider the following function definition:
void
tripler(int& n) { n = 3*n; }
Which of the following are acceptable function calls?
int
a[3] = {4, 5, 6}, number = 2; tripler(number); tripler(a[2]); tripler(a[3]); tripler(a[number]); tripler(a);
What (if anything) is wrong with the following code? The definition of tripler
is given in Self-Test Exercise 11.
int
b[5] = {1, 2, 3, 4, 5};
for
(int
i = 1; i <= 5; i++) tripler(b[i]);
A function can have a formal parameter for an entire array so that when the function is called, the argument that is plugged in for this formal parameter is an entire array. However, a formal parameter for an entire array is neither a call-by-value parameter nor a call-by-reference parameter; it is a new kind of formal parameter referred to as an array parameter. Let’s start with an example.
The function defined in Display 7.4 has one array parameter, a
, which will be replaced by an entire array when the function is called. It also has one ordinary call-by-value parameter (size
) that is assumed to be an integer value equal to the size of the array. This function fills its array argument (that is, fills all the array’s indexed variables) with values typed in from the keyboard, and then the function outputs a message to the screen telling the index of the last array index used.
The formal parameter int a[ ]
is an array parameter. The square brackets, with no index expression inside, are what C++ uses to indicate an array parameter. An array parameter is not quite a call-by-reference parameter, but for most practical purposes it behaves very much like a call-by-reference parameter. Let’s go through this example in detail to see how an array argument works in this case. (An array argument is, of course, an array that is plugged in for an array parameter, such as a[ ]
.)
When the function fillUp
is called it must have two arguments: The first gives an array of integers, and the second should give the declared size of the array. For example, the following is an acceptable function call:
int
score[5], numberOfScores = 5; fillUp(score, numberOfScores);
This call to fillUp
will fill the array score
with five integers typed in at the keyboard. Notice that the formal parameter a[ ]
(which is used in the function declaration and the heading of the function definition) is given with square brackets, but no index expression. (You may insert a number inside the square brackets for an array parameter, but the compiler will simply ignore the number, so we do not use such numbers in this book.) On the other hand, the argument given in the function call (score
in this example) is given without any square brackets or any index expression. What happens to the array argument score
in this function call? Very loosely speaking, the argument score
is plugged in for the formal array parameter a
in the body of the function, and then the function body is executed. Thus, the function call
Function Declaration
1
void
fillUp(int a[],
int
size); 2
//Precondition: size is the declared size of the array a.
3
//The user will type in size integers.
4
//Postcondition: The array a is filled with size integers
5
//from the keyboard.
Function Definition
1
//Uses iostream:
2
void
fillUp(int a[],int
size) 3 { 4
using namespace
std; 5 cout << "Enter " << size << " numbers:\n"; 6
for
(int
i = 0; i < size; i++) 7 cin >> a[i]; 8 size−−; 9 cout << "The last array index used is " << size << endl; 10 }
fillUp(score, numberOfScores);
is equivalent to the following code:
The formal parameter a
is a different kind of parameter from the ones we have seen before now. The formal parameter a
is merely a placeholder for the argument score
. When the function fillUp
is called with score
as the array argument, the computer behaves as if a
were replaced with the corresponding argument score
. When an array is used as an argument in a function call, any action that is performed on the array parameter is performed on the array argument, so the values of the indexed variables of the array argument can be changed by the function. If the formal parameter in the function body is changed (for example, with a cin
statement), then the array argument will be changed.
So far it looks like an array parameter is simply a call-by-reference parameter for an array. That is close to being true, but an array parameter is slightly different from a call-by-reference parameter. To help explain the difference, let’s review some details about arrays.
Recall that an array is stored as a contiguous chunk of memory. For example, consider the following declaration for the array score
:
int
score[5];
When you declare this array, the computer reserves enough memory to hold five variables of type int
, which are stored one after the other in the computer’s memory. The computer does not remember the addresses of each of these five indexed variables; it remembers only the address of indexed variable score[0]
. For example, when your program needs score[3]
, the computer calculates the address of score[3]
from the address of score[0]
. The computer knows that score[3]
is located three int
variables past score[0]
. Thus, to obtain the address of score[3]
, the computer takes the address of score[0]
and adds a number that represents the amount of memory used by three int
variables; the result is the address of score[3]
.
Viewed this way, an array has three parts: the address (location in memory) of the first indexed variable, the base type of the array (which determines how much memory each indexed variable uses), and the size of the array (that is, the number of indexed variables). When an array is used as an array argument to a function, only the first of these three parts is given to the function. When an array argument is plugged in for its corresponding formal parameter, all that is plugged in is the address of the array’s first indexed variable. The base type of the array argument must match the base type of the formal parameter, so the function also knows the base type of the array. However, the array argument does not tell the function the size of the array. When the code in the function body is executed, the computer knows where the array starts in memory and how much memory each indexed variable uses, but (unless you make special provisions) it does not know how many indexed variables the array has. That is why it is critical that you always have another int
argument telling the function the size of the array. That is also why an array parameter is not the same as a call-by-reference parameter. You can think of an array parameter as a weak form of call-by-reference parameter in which everything about the array is told to the function except for the size of the array.2
These array parameters may seem a little strange, but they have at least one very nice property as a direct result of their seemingly strange definition. This advantage is best illustrated by again looking at our example of the function fillUp
given in Display 7.4. That same function can be used to fill an array of any size, as long as the base type of the array is int
. For example, suppose you have the following array declarations:
int
score[5], time[10];
The first of the following calls to fillUp
fills the array score
with five values and the second fills the array time
with ten values:
fillUp(score, 5);
fillUp(time, 10);
You can use the same function for array arguments of different sizes because the size is a separate argument.
const
Parameter ModifierWhen you use an array argument in a function call, the function can change the values stored in the array. This is usually fine. However, in a complicated function definition, you might write code that inadvertently changes one or more of the values stored in an array, even though the array should not be changed at all. As a precaution, you can tell the compiler that you do not intend to change the array argument, and the computer will then check to make sure your code does not inadvertently change any of the values in the array. To tell the compiler that an array argument should not be changed by your function, you insert the modifier const
before the array parameter for that argument position. An array parameter that is modified with a const
is called a constant array parameter.
For example, the following function outputs the values in an array but does not change the values in the array:
void
showTheWorld(int
a[ ],
int
sizeOfA)
//Precondition: sizeOfA is the declared size of the array a. //All indexed variables of a have been given values. //Postcondition: The values in a have been written //to the screen.
{ cout << "The array contains the following values:\n";
for
(int
i = 0; i < sizeOfA; i++) cout << a[i] << " "; cout << endl; }
This function will work fine. However, as an added safety measure you can add the modifier const
to the function heading as follows:
void
showTheWorld(const int
a[ ],
int
sizeOfA)
With the addition of this modifier const
, the computer will issue an error message if your function definition contains a mistake that changes any of the values in the array argument. For example, the following is a version of the function showTheWorld
that contains a mistake that inadvertently changes the value of the array argument. Fortunately, this version of the function definition includes the modifier const
, so that an error message will tell us that the array a
is changed. This error message will help to explain the mistake:
void
showTheWorld(const int
a[ ],
int
sizeOfA)
//Precondition: sizeOfA is the declared size of the array a. //All indexed variables of a have been given values. //Postcondition: The values in a have been written //to the screen.
If we had not used the const
modifier in this function definition and if we made the mistake shown, the function would compile and run with no error messages. However, the code would contain an infinite loop that continually increments a[0]
and writes its new value to the screen.
The problem with this incorrect version of showTheWorld
is that the wrong item is incremented in the for
loop. The indexed variable a[i]
is incremented, but it should be the index i
that is incremented. In this incorrect version, the index i
starts with the value 0
and that value is never changed. But a[i]
, which is the same as a[0]
, is incremented. When the indexed variable a[i]
is incremented, that changes a value in the array, and since we included the modifier const
, the computer will issue a warning message. That error message should serve as a clue to what is wrong.
You normally have a function declaration in your program in addition to the function definition. When you use the const
modifier in a function definition, you must also use it in the function declaration so that the function heading and the function declaration are consistent.
The modifier const
can be used with any kind of parameter, but it is normally used only with array parameters and call-by-reference parameters for classes, which are discussed in Chapter 11.
A function may not return an array in the same way that it returns a value of type int
or double
. There is a way to obtain something more or less equivalent to a function that returns an array. The thing to do is to return a pointer to the array. However, we have not yet covered pointers. We will discuss returning a pointer to an array when we discuss the interaction of arrays and pointers in Chapter 9. Until then, you have no way to write a function that returns an array.
In this case study we use arrays in the top-down design of a program. We use both indexed variables and entire arrays as arguments to the functions for subtasks.
The Apex Plastic Spoon Manufacturing Company has commissioned us to write a program that will display a bar graph showing the productivity of each of its four manufacturing plants for any given week. Plants keep separate production figures for each department, such as the teaspoon department, soup spoon department, plain cocktail spoon department, colored cocktail spoon department, and so forth. Moreover, each plant has a different number of departments. For example, only one plant manufactures colored cocktail spoons. The input is entered plant-by-plant and consists of a list of numbers giving the production for each department in that plant. The output will consist of a bar graph in the following form:
Plant #1 **********
Plant #2 *************
Plant #3 *******************
Plant #4 *****
Each asterisk represents 1000 units of output.
We decide to read in the input separately for each department in a plant. Since departments cannot produce a negative number of spoons, we know that the production figure for each department will be nonnegative. Hence, we can use a negative number as a sentinel value to mark the end of the production numbers for each plant.
Since output is in units of 1000, it must be scaled by dividing it by 1000. This presents a problem since the computer must display a whole number of asterisks. It cannot display 1.6 asterisks for 1600 units. We will thus round to the nearest 1000th. Thus, 1600 will be the same as 2000 and will produce two asterisks. A precise statement of the program’s input and output is as follows.
Input
There are four manufacturing plants numbered 1 through 4. The following input is given for each of the four plants: a list of numbers giving the production for each department in that plant. The list is terminated with a negative number that serves as a sentinel value.
Output
A bar graph showing the total production for each plant. Each asterisk in the bar graph equals 1000 units. The production of each plant is rounded to the nearest 1000 units.
We will use an array called production
, which will hold the total production for each of the four plants. In C++, array indexes always start with 0
. But since the plants are numbered 1
through 4
, rather than 0
through 3
, we will not use the plant number as the array index. Instead, we will place the total production for plant number n
in the indexed variable production[n
−1]
. The total output for plant number 1 will be held in production[0]
, the figures for plant 2 will be held in production[1]
, and so forth.
Since the output is in thousands of units, the program will scale the values of the array elements. If the total output for plant number 3 is 4040 units, then the value of production[2]
will initially be set to 4040
. This value of 4040
will then be scaled to 4
so that the value of production[2]
is changed to 4
, and four asterisks will be output in the graph to represent the output for plant number 3.
The task for our program can be divided into the following subtasks:
inputData
: Read the input data for each plant and set the value of the indexed variable production[plantNumber − 1]
equal to the total production for that plant, where plantNumber
is the number of the plant.
scale: For each plantNumber
, change the value of the indexed variable production[plantNumber − 1]
to the correct number of asterisks.
graph
: Output the bar graph.
The entire array production
will be an argument for the functions that carry out these subtasks. As is usual with an array parameter, this means we must have an additional formal parameter for the size of the array, which in this case is the same as the number of plants. We will use a defined constant for the number of plants, and this constant will serve as the size of the array production
. The main
part of our program, together with the function declarations for the functions that perform the subtasks and the defined constant for the number of plants, is shown in Display 7.5. Notice that, since there is no reason to change the array parameter to the function graph
, we have made that array parameter a constant parameter by adding the const
parameter modifier. The material in Display 7.5 is the outline for our program, and if it is in a separate file, that file can be compiled so that we can check for any syntax errors in this outline before we go on to define the functions corresponding to the function declarations shown.
Having compiled the file shown in Display 7.5, we are ready to design the implementation of the functions for the three subtasks. For each of these three functions, we will design an algorithm, write the code for the function, and test the function before we go on to design the next function.
inputData
The function declaration and descriptive comment for the function inputData
is shown in Display 7.5. As indicated in the body of the main
part of our program (also shown in Display 7.5), when inputData
is called, the formal array parameter a
will be replaced with the array production
, and since the last plant number is the same as the number of plants, the formal parameter lastPlantNumber
will be replaced by NUMBER_OF_PLANTS
. The algorithm for inputData
is straightforward:
For plantNumber
equal to each of 1
, 2
, through lastPlantNumber
do the following:
Read in all the data for plant whose number is plantNumber
.
Sum the numbers.
Set production[plantNumber
−1]
equal to that total.
inputData
The algorithm for the function inputData
translates to the following code:
//Uses iostream:
void
inputData(int
a[ ],
int
lastPlantNumber) {
using namespace
std;
for
(int
plantNumber = 1; plantNumber <= lastPlantNumber; plantNumber++) { cout << endl << "Enter production data for plant number " << plantNumber << endl; getTotal(a[plantNumber − 1]); } }
The code is routine since all the work is done by the function getTotal,
which we still need to design. But before we move on to discuss the function getTotal,
let’s observe a few things about the function inputData.
Notice that we store the figures for plant number plantNumber
in the indexed variable with index plantNumber
− 1
; this is because arrays always start with index 0
, while the plant numbers start with 1
. Also, notice that we use an indexed variable for the argument to the function getTotal.
The function getTotal
really does all the work for the function inputData.
The function getTotal
does all the input work for one plant. It reads the production figures for that plant, sums the figures, and stores the total in the indexed variable for that plant. But getTotal
does not need to know that its argument is an indexed variable. To a function such as getTotal,
an indexed variable is just like any other variable of type int
. Thus, getTotal
will have an ordinary call-by-reference parameter of type int
. That means that getTotal
is just an ordinary input function like others that we have seen before we discussed arrays. The function getTotal
reads in a list of numbers ended with a sentinel value, sums the numbers as it reads them in, and sets the value of its argument, which is a variable of type int
, equal to this sum. There is nothing new to us in the function getTotal
. Display 7.6 shows the function definitions for both getTotal
and inputData
. The functions are embedded in a simple test program.
1
//Reads data and displays a bar graph showing productivity for each plant.
2 #include <iostream> 3
const int
NUMBER_OF_PLANTS = 4; 4 5
void
inputData(int
a[],
int
lastPlantNumber); 6
//Precondition: lastPlantNumber is the declared size of the array a.
7
//Postcondition: For plantNumber = 1 through lastPlantNumber:
8
//a[plantNumber − 1] equals the total production for plant number plantNumber.
9 10
void
scale(int
a[],
int
size); 11
//Precondition: a[0] through a[size − 1] each has a nonnegative value.
12
//Postcondition: a[i] has been changed to the number of 1000s (rounded to
13
//an integer) that were originally in a[i], for all i such that 0 <= i <= size − 1.
14 15
void
graph(const int
asteriskCount[],
int
lastPlantNumber); 16
//Precondition: asteriskCount[0] through asteriskCount[lastPlantNumber − 1]
17
//have nonnegative values.
18
//Postcondition: A bar graph has been displayed saying that plant
19
//number N has produced asteriskCount[N − 1] 1000s of units, for each N such that
20
//1 <= N <= lastPlantNumber
21 22
int
main( ) 23 { 24
using namespace
std; 25
int
production[NUMBER_OF_PLANTS]; 26 27 cout << "This program displays a graph showing\n" 28 << "production for each plant in the company.\n"; 29 30 inputData(production, NUMBER_OF_PLANTS); 31 scale(production, NUMBER_OF_PLANTS); 32 graph(production, NUMBER_OF_PLANTS); 33 34
return
0; 35 } 36
inputData
Every function should be tested in a program in which it is the only untested function. The function inputData
includes a call to the function getTotal
. Therefore, we should test getTotal
in a driver program of its own. Once getTotal
has been completely tested, we can use it in a program, like the one in Display 7.6, to test the function inputData
.
When testing the function inputData
, we should include tests with all possible kinds of production figures for a plant. We should include a plant that has no production figures (as we did for plant 4 in Display 7.6); we should include a test for a plant with only one production figure (as we did for plant 3 in Display 7.6); and we should include a test for a plant with more than one production figure (as we did for plants 1 and 2 in Display 7.6). We should test for both nonzero and zero production figures, which is why we included a 0
in the input list for plant 2 in Display 7.6.
scale
The function scale
changes the value of each indexed variable in the array production
so that it shows the number of asterisks to print out. Since there should be one asterisk for every 1000 units of production, the value of each indexed variable must be divided by 1000.0
. Then to get a whole number of asterisks, this number is rounded to the nearest integer. This method can be used to scale the values in any array a
of any size, so the function declaration for scale
, shown in Display 7.5 and repeated here, is stated in terms of an arbitrary array a
of some arbitrary size:
void
scale(int
a[ ],
int
size);
//Precondition: a[0] through a[size − 1] each has a //nonnegative value. //Postcondition: a[i] has been changed to the number of 1000s //(rounded to an integer) that were originally in a[i], for //all i such that 0 <= i <= size − 1.
When the function scale
is called, the array parameter a
will be replaced by the array production
, and the formal parameter size
will be replaced by NUMBER_OF_PLANTS
so that the function call looks like the following:
scale(production, NUMBER_OF_PLANTS);
The algorithm for the function scale
is as follows:
for
(int
index = 0; index < size; index++)
Divide the value of a[index]
by 1000 and round the result to the nearest whole number; the result is the new value of a[index]
.
scale
The algorithm for scale
translates into the C++ code given next, where round
is a function we still need to define. The function round
takes one argument of type double
and returns a type int
value that is the integer nearest to its argument; that is, the function round
will round its argument to the nearest whole number.
1 //Tests the function inputData.
2 #include <iostream>
3 const int NUMBER_OF_PLANTS = 4;
4
5 void inputData(int a[], int lastPlantNumber);
6 //Precondition: lastPlantNumber is the declared size of the array a.
7 //Postcondition: For plantNumber = 1 through lastPlantNumber:
8 //a[plantNumber − 1] equals the total production for plant number plantNumber.
9
10 void getTotal(int& sum);
11 //Reads nonnegative integers from the keyboard and
12 //places their total in sum.
13
14 int main( )
15 {
16 using namespace std;
17 int production[NUMBER_OF_PLANTS];
18 char ans;
19
20 do
21 {
22 inputData(production, NUMBER_OF_PLANTS);
23 cout << endl
24 << "Total production for each"
25 << " of plants 1 through 4:\n";
26 for (int number = 1; number <= NUMBER_OF_PLANTS; number++)
27 cout << production[number − 1] << " ";
28
29 cout << endl
30 << "Test Again?(Type y or n and Return): ";
31 cin >> ans;
32 } while ( (ans != 'N') && (ans != 'n') );
33
34 cout << endl;
35
36 return 0;
37 }
38 //Uses iostream:
39 void inputData(int a[], int lastPlantNumber)
40 {
41 using namespace std;
42 for (int plantNumber = 1;
43 plantNumber <= lastPlantNumber; plantNumber++)
44 {
45 cout << endl
46 << "Enter production data for plant number "
47 << plantNumber << endl;
48 getTotal(a[plantNumber − 1]);
49 }
50 }
51
52
53 //Uses iostream:
54 void getTotal(int& sum)
55 {
56 using namespace std;
57 cout << "Enter number of units produced by each department.\n"
58 << "Append a negative number to the end of the list.\n";
59
60 sum = 0;
61 int next;
62 cin >> next;
63 while (next >= 0)
64 {
65 sum = sum + next;
66 cin >> next;
67 }
68
69 cout << "Total = " << sum << endl;
70 }
Sample Dialogue
Enter production data for plant number 1 Enter number of units produced by each department. Append a negative number to the end of the list. 1 2 3 −1 Total = 6 Enter production data for plant number 2 Enter number of units produced by each department. Append a negative number to the end of the list. 0 2 3 −1 Total = 5 Enter production data for plant number 3 Enter number of units produced by each department. Append a negative number to the end of the list. 2 −1 Total = 2 Enter production data for plant number 4 Enter number of units produced by each department. Append a negative number to the end of the list. −1 Total = 0 Total production for each of plants 1 through 4: 6 5 2 0 Test Again?(Type y or n and Return): n
void
scale(int
a[],
int
size) {
for
(int
index = 0; index < size; index++) a[index] = roundNum(a[index]/1000.0 ); }
Notice that we divided by 1000.0
, not by 1000
(without the decimal point). If we had divided by 1000
, we would have performed integer division. For example, 2600/1000
would give the answer 2
, but 2600/1000.0
gives the answer 2.6
. It is true that we want an integer for the final answer after rounding, but we want 2600
divided by 1000
to produce 3
, not 2
, when it is rounded to a whole number.
We now turn to the definition of the function roundNum
, which rounds its argument to the nearest integer. For example, roundNum(2.3)
returns 2
, and roundNum(2.6)
returns 3
. The code for the function roundNum
, as well as that for scale
, is given in Display 7.7. The code for round
may require a bit of explanation.
The function roundNum
uses the predefined function floor
from the library with the header file cmath
. The function floor
returns the whole number just below its argument. For example, floor(2.1)
and floor(2.9)
both return 2
. To see that roundNum
works correctly, let’s look at some examples. Consider roundNum(2.4)
. The value returned is
floor(2.4 + 0.5)
which is floor(2.9)
, and that is 2.0
. In fact, for any number that is greater than or equal to 2.0
and strictly less than 2.5
, that number plus 0.5
will be less than 3.0
, and so floor
applied to that number plus 0.5
will return 2.0
. Thus, round
applied to any number that is greater than or equal to 2.0
and strictly less than 2.5
will return 2
. (Since the function declaration for round
specifies that the type for the value returned is int
, the computed value of 2.0
is type cast to the integer value 2
without a decimal point using static_cast<int>
.)
Now consider numbers greater than or equal to 2.5
, for example, 2.6
. The value returned by the call roundNum(2.6)
is
floor(2.6 + 0.5)
The Function
scale
1 //Demonstration program for the function scale.
2 #include <iostream>
3 #include <cmath>
4
5 void scale(int a[], int size);
6
//Precondition: a[0] through a[size − 1] each has a nonnegative value.
7 //Postcondition: a[i] has been changed to the number of 1000s (rounded to
8 //an integer) that were originally in a[i], for all i such that 0 <= i <= size − 1.
9
10 int roundNum(double number);
11 //Precondition: number >= 0.
12 //Returns number rounded to the nearest integer.
13
14 int main( )
15 {
16 using namespace std;
17 int someArray[4], index;
18 cout << "Enter 4 numbers to scale: ";
19 for (index = 0; index < 4; index++)
20 cin >> someArray[index];
21 scale(someArray, 4);
22 cout << "Values scaled to the number of 1000s are: ";
23 for (index = 0; index < 4; index++)
24 cout << someArray[index] << " ";
25 cout << endl;
26 return 0;
27 }
28
29 void scale(int a[], int size)
30 {
31 for (int index = 0; index < size; index++)
32 a[index] = roundNum(a[index]/1000.0);
33 }
34
35 //Uses cmath:
36 int roundNum(double number)
37 {
38 using namespace std;
39 return static_cast<int>(floor(number + 0.5));
40 }
Sample Dialogue
Enter 4 numbers to scale: 2600 999 465 3501
Values scaled to the number of 1000s are: 3 1 0 4
which is floor(3.1)
and that is 3.0
. In fact, for any number that is greater than or equal to 2.5
and less than or equal to 3.0
, that number plus 0.5
will be greater than 3.0
. Thus, roundNum
called with any number that is greater than or equal to 2.5
and less than or equal to 3.0
will return 3
.
Thus, roundNum
works correctly for all arguments between 2.0
and 3.0
. Clearly, there is nothing special about arguments between 2.0
and 3.0
. A similar argument applies to all nonnegative numbers. So, roundNum
works correctly for all nonnegative arguments.
scale
Display 7.7 contains a demonstration program for the function scale
, but the testing programs for the functions round
and scale
should be more elaborate than this simple program. In particular, they should allow you to retest the tested function several times rather than just once. We will not give the complete testing programs, but you should first test round
(which is used by scale
) in a driver program of its own, and then test scale
in a driver program. The program to test round
should test arguments that are 0
, arguments that round up (like 2.6
), and arguments that round down like 2.3
. The program to test scale
should test a similar variety of values for the elements of the array.
graph
The complete program for producing the desired bar graph is shown in Display 7.8. We have not taken you step-by-step through the design of the function graph
because it is quite straightforward.
Production Graph Program
1 //Reads data and displays a bar graph showing productivity for each plant.
2 #include <iostream>
3 #include <cmath>
4 const int NUMBER_OF_PLANTS = 4;
5 void inputData(int a[], int lastPlantNumber);
6 //Precondition: lastPlantNumber is the declared size of the array a.
7 //Postcondition: For plantNumber = 1 through lastPlantNumber:
8 //a[plantNumber − 1] equals the total production for plant number plantNumber.
9 void scale(int a[], int size);
10 //Precondition: a[0] through a[size − 1] each has a nonnegative value.
11 //Postcondition: a[i] has been changed to the number of 1000s (rounded to
12 //an integer) that were originally in a[i], for all i such that 0 <= i <= size − 1.
13 void graph(const int asteriskCount[], int lastPlantNumber);
14 //Precondition: asteriskCount[0] through asteriskCount[lastPlantNumber − 1]
15 //have nonnegative values.
16 //Postcondition: A bar graph has been displayed saying that plant
17 //number N has produced asteriskCount[N − 1] 1000s of units, for each N such that
18 //1 <= N <= lastPlantNumber
19 void getTotal(int& sum);
20 //Reads nonnegative integers from the keyboard and
21 //places their total in sum.
22 int roundNum(double number);
23 //Precondition: number >= 0.
24 //Returns number rounded to the nearest integer.
25 void printAsterisks(int n);
26 //Prints n asterisks to the screen.
27 int main( )
28 {
29 using namespace std;
30 int production[NUMBER_OF_PLANTS];
31 cout << "This program displays a graph showing\n"
32 << "production for each plant in the company.\n";
33 inputData(production, NUMBER_OF_PLANTS);
34 scale(production, NUMBER_OF_PLANTS);
35 graph(production, NUMBER_OF_PLANTS);
36 return 0;
37 }
38 //Uses iostream:
39 void inputData(int a[], int lastPlantNumber)
<The rest of the definition of inputData is given in Display 7.6.>
40 //Uses iostream:
41 void getTotal(int& sum)
<The rest of the definition of getTotal is given in Display 7.6.>
42 void scale(int a[], int size)
<The rest of the definition of scale is given in Display 7.7.>
43 //Uses cmath:
44 int roundNum(double number)
<The rest of the definition of round is given in Display 7.7.>
45 //Uses iostream:
46 void graph(const int asteriskCount[], int lastPlantNumber)
47 {
48 using namespace std;
49 cout << "\nUnits produced in thousands of units:\n";
50 for (int plantNumber = 1;
51 plantNumber <= lastPlantNumber; plantNumber++)
52 {
53 cout << "Plant #" << plantNumber << " ";
54 printAsterisks(asteriskCount[plantNumber − 1]);
55 cout << endl;
56 }
57 }
58 //Uses iostream:
59 void printAsterisks(int n)
60 {
61 using namespace std;
62 for (int count = 1; count <= n; count++)
63 cout << "*";
64 }
Sample Dialogue
This program displays a graph showing production for each plant in the company. Enter production data for plant number 1 Enter number of units produced by each department. Append a negative number to the end of the list. 2000 3000 1000 −1 Total = 6000 Enter production data for plant number 2 Enter number of units produced by each department. Append a negative number to the end of the list. 2050 3002 1300 −1 Total = 6352 Enter production data for plant number 3 Enter number of units produced by each department. Append a negative number to the end of the list. 5000 4020 500 4348 −1 Total = 13868 Enter production data for plant number 4 Enter number of units produced by each department. Append a negative number to the end of the list. 2507 6050 1809 −1 Total = 10366 Units produced in thousands of units: Plant #1 ****** Plant #2 ****** Plant #3 ************** Plant #4 **********
Write a function definition for a function called one_more
, which has a formal parameter for an array of integers and increases the value of each array element by one. Add any other formal parameters that are needed.
Consider the following function definition:
void
too2(int
a[ ],
int
howMany) {
for
(int
index = 0; index < howMany; index++) a[index] = 2; }
Which of the following are acceptable function calls?
int
myArray[29]; too2(myArray, 29); too2(myArray, 10); too2(myArray, 55); "Hey too2. Please, come over here."
int
yourArray[100]; too2(yourArray, 100); too2(myArray[3], 29);
Insert const
before any of the following array parameters that can be changed to constant array parameters:
void
output(double
a[],
int
size);
//Precondition: a[0] through a[size − 1] have values. //Postcondition: a[0] through a[size − 1] have been //written out.
void
dropOdd(int
a[ ],
int
size);
//Precondition: a[0] through a[size − 1] have values. //Postcondition: All odd numbers in a[0] through //a[size − 1] have been changed to 0.
Write a function named outOfOrder
that takes as parameters an array of double
s and an int
parameter named size
and returns a value of type int
. This function will test this array for being out of order, meaning that the array violates the following condition:
a[0] <= a[1] <= a[2] <= ...
The function returns −1 if the elements are not out of order; otherwise, it will return the index of the first element of the array that is out of order. For example, consider the declaration
double
a[10] = {1.2, 2.1, 3.3, 2.5, 4.5, 7.9, 5.4, 8.7, 9.9, 1.0};
In this array, a[2]
and a[3]
are the first pair out of order, and a[3]
is the first element out of order, so the function returns 3
. If the array were sorted, the function would return −1
.