Partially Filled Arrays

A full-length problem involving the use of arrays that are always filled is considered here. This problem is from our textbook, but it contains a major design flaw (see if you can spot it). The second example illustrates the use of partially-filled arrays.

  1. Detailed analysis of the problem:

    • Problem background:
      A certain manufacturing company has 4 plants (factories). Each plant has a number of departments. Each department produces a certain number of items per day.
    • Input:
      For each of the 4 plants, a list of numbers giving the production of each department are read in. The list is terminated with a negative number that serves as a sentinel value.
    • Output:
      A bar chart showing the total production for each plant is displayed on the screen. The bar is drawn with asterisks and each asterisk represents 1000 items. The production of each plant is rounded off to the nearest 1000 items.

  2. Divide the program into 3 subtasks:
    • Input data: For plant 1 to 4, read the production for each department and accumulate the production in a sum to obtain the total production for the plant. A negative number is used as sentinel.
    • Scale the total production for each plant to obtain the number of asterisks to plot.
    • Draw the bar chart.

  3. The following is an outline of the program. It has the main part as well as function prototypes. This file can be compiled and checked for syntax errors before any function definitions are written.

    //Reads data and displays a bar graph (displayed side-way) showing productivity for each plant.
    #include <iostream>
    using namespace std;

    const int NUMBER_OF_PLANTS = 4;

    void input_data(int a[ ], int last_plant_number);
    //Precondition: last_plant_number is the declared size of the array a.
    //Postcondition: For plant_number 1 through last_plant_number:
    //a[plant_number-1] = the total production for plant number plant_number.

    void scale(int a[ ], int size);
    //Precondition: a[0] through a[size-1] each have 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.

    void graph(const int asterisk_count[ ], int last_plant_number);
    //Precondition: a[0] through a[last_plant_number-1] have nonnegative values.
    //Postcondition: A bar graph has been displayed saying that plant
    //number N has produced a[N-1] 1000s of units, for each N such that
    //1 <= N <= last_plant_number

    int main( )
    {
        int production[NUMBER_OF_PLANTS];

        cout << "This program displays a graph showing\n"
                << "production for each plant in the company.\n";

        input_data(production, NUMBER_OF_PLANTS);
        scale(production, NUMBER_OF_PLANTS);
        graph(production, NUMBER_OF_PLANTS);

        return 0;
    }

  4. The following can be used to test the function definition for input_data.

    //Tests the function input_data.
    #include <iostream>
    using namespace std;

    const int NUMBER_OF_PLANTS = 4;

    void input_data(int a[ ], int last_plant_number);
    //Precondition: last_plant_number is the declared size of the array a.
    //Postcondition: For plant_number = 1 through last_plant_number:
    //a[plant_number-1] = the total production for plant number plant_number.
    //This function calls the get_total function.

    void get_total(int& sum);
    //Reads nonnegative integers from the keyboard and
    //places their total in sum.

    int main( )
    {
        int production[NUMBER_OF_PLANTS];
        char ans;

        do
        {
            input_data(production, NUMBER_OF_PLANTS);
            cout << endl
                    << "Total production for each"
                    << " of plants 1 through 4:\n";
            for (int number = 1; number <= NUMBER_OF_PLANTS; number++)
                cout << production[number - 1] << " ";

                cout << endl << "Test Again?(Type y or n and return): ";
                cin >> ans;
        } while ( (ans != 'N') && (ans != 'n') );

        cout << endl;
        return 0;
    }


    //Uses iostream:
    void input_data(int a[ ], int last_plant_number)
    {
        for (int plant_number = 1; plant_number <= last_plant_number;
                    plant_number++)
        {
            cout << endl
                    << "Enter production data for plant number "
                    << plant_number << endl;
            get_total(a[plant_number - 1]);
        }
    }


    //Uses iostream:
    void get_total(int& sum)
    {
        cout << "Enter number of units produced by each department.\n"
                << "Append a negative number to the end of the list.\n";

        sum = 0;
        int next;
        cin >> next;
        while (next >= 0)
        {
            sum += next;
            cin >> next;
        }

        cout << "Total = " << sum << endl;
    }


  5. The following can be used to test the function definition for the function scale.

    //Demonstration program for the function scale.
    #include <iostream>
    #include <cmath>
    using namespace std;

    void scale(int a[ ], int size);
    //Precondition: a[0] through a[size-1] each have 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

    int round(double number);
    //Precondition: number >= 0.
    //Returns number rounded to the nearest integer.

    int main( )
    {
        int some_array[4], index;

        cout << "Enter 4 numbers to scale: ";
        for (index = 0; index < 4; index++)
        cin >> some_array[index];

        scale(some_array, 4);

        cout << "Values scaled to the number of 1000s are: ";
        for (index = 0; index < 4; index++)
            cout << some_array[index] << " ";
        cout << endl;

        return 0;
    }

    void scale(int a[ ], int size)
    {
        for (int index = 0; index < size; index++)
            a[index] = round(a[index]/1000.0);
    }

    //Uses math:
    int round(double number)
    {
        return floor(number + 0.5); // }

  6. This is the final full-length version of the program:

    //Reads data and displays a bar graph showing productivity for each plant.
    #include <iostream>
    #include <cmath>
    using namespace std;

    const int NUMBER_OF_PLANTS = 4;

    void input_data(int a[ ], int last_plant_number);
    //Precondition: last_plant_number is the declared size of the array a.
    //Postcondition: For plant_number = 1 through last_plant_number:
    //a[plant_number-1] = the total production for plant number plant_number.

    void scale(int a[ ], int size);
    //Precondition: a[0] through a[size-1] each have 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

    void graph(const int asterisk_count[ ], int last_plant_number);
    //Precondition: a[0] through a[last_plant_number-1] have nonnegative values.
    //Postcondition: A bar graph has been displayed saying that plant
    //number N has produced a[N-1] 1000s of units, for each N such that
    //1 <= N <= last_plant_number

    void get_total(int& sum);
    //Reads nonnegative integers from the keyboard and
    //places their total in sum.

    int round(double number);
    //Precondition: number >= 0.
    //Returns number rounded to the nearest integer.

    void print_asterisks(int n);
    //Prints n asterisks to the screen.

    int main( )
    {
        int production[NUMBER_OF_PLANTS];

        cout << "This program displays a graph showing\n"
                    << "production for each plant in the company.\n";
        input_data(production, NUMBER_OF_PLANTS);
        scale(production, NUMBER_OF_PLANTS);
        graph(production, NUMBER_OF_PLANTS);
        return 0;
    }

    //Uses iostream:
    void input_data(int a[ ], int last_plant_number)
    {
        for (int plant_number = 1; plant_number <= last_plant_number;                 plant_number++)
        {
            cout << endl
                    << "Enter production data for plant number "
                    << plant_number << endl;
            get_total(a[plant_number - 1]);
        }
    }

    //Uses iostream:
    void get_total(int& sum)
    {
        cout << "Enter number of units produced by each department.\n"
                    << "Append a negative number to the end of the list.\n";

        sum = 0;
        int next;
        cin >> next;
        while (next >= 0)
        {
            sum += next;
            cin >> next;
        }

        cout << "Total = " << sum << endl;
    }


    void scale(int a[ ], int size)
    {
        for (int index = 0; index < size; index++)
            a[index] = round(a[index]/1000.0);
    }


    //Uses cmath:
    int round(double number)
    {
        return floor(number + 0.5); //use casting to avoid compiler warning
    }

    //Uses iostream:
    void graph(const int asterisk_count[ ], int last_plant_number)
    {
        cout << "\nUnits produced in thousands of units:\n";
        for(int plant_number = 1; plant_number <= last_plant_number;
                    plant_number++)
        {
            cout << "Plant #" << plant_number << " ";
            print_asterisks(asterisk_count[plant_number - 1]);
            cout << endl;
        }
    }

    //Uses iostream:
    void print_asterisks(int n)
    {
        for (int count = 1; count <= n; count++)
            cout << "*";
    }


The following example illustrates how partial arrays can be handled.

//Shows the difference between each of a list of golf scores and their average.
#include <iostream>
using namespace std;

const int MAX_NUMBER_SCORES = 10;

void fill_array(int a[ ], int size, int& number_used);
//Precondition: size is the declared size of the array a.
//Postcondition: number_used is the number of values stored in a.
//a[0] through a[number_used-1] have been filled with
//nonnegative integers read from the keyboard.

double compute_average(const int a[ ], int number_used);
//Precondition: a[0] through a[number_used-1] have values; number_used > 0.
//Returns the average of numbers a[0] through a[number_used-1].

void show_difference(const int a[ ], int number_used);
//Precondition: The first number_used indexed variables of a have values.
//Postcondition: Gives screen output showing how much each of
//the first number_used elements of a differ from their average.

int main( )
{
    int score[MAX_NUMBER_SCORES], number_used;

    cout << "This program reads golf scores and shows\n"
                << "how much each differs from the average.\n";

    cout << "Enter golf scores:\n";
    fill_array(score, MAX_NUMBER_SCORES, number_used);
    show_difference(score, number_used);

    return 0;
}

//Uses iostream:
void fill_array(int a[ ], int size, int& number_used)
{
    cout << "Enter up to " << size << " nonnegative whole numbers.\n"
                << "Mark the end of the list with a negative number.\n";

    int next, index = 0;
    cin >> next;
    while ((next >= 0) && (index < size))
    {
        a[index] = next;
        index++;
        cin >> next;
    }

    number_used = index;
}

double compute_average(const int a[ ], int number_used)
{
    double total = 0;
    for (int index = 0; index < number_used; index++)
        total += a[index];
    if (number_used > 0)
    {
        return (total/double(number_used));
    }
    else
    {
        cout << "ERROR: number of elements is 0 in compute_average.\n"
                << "compute_average returns 0.\n";
        return 0;
    }
}

void show_difference(const int a[ ], int number_used)
{
    double average = compute_average(a, number_used);
    cout << "Average of the " << number_used
                << " scores = " << average << endl
                << "The scores are:\n";
    for (int index = 0; index < number_used; index++)
        cout << a[index] << " differs from average by "
                    << (a[index] - average) << endl;
    }