robocop1 robocop1 - 7 days ago 7
C++ Question

Cannot display proper percentage, or total from array in for loops

The problem I am having with my program is, first, when I calculate percent, it's not adding all the elements in the array to a total and diving them from. I tried putting the total += percents[i]; in a nested for-loop, but it just gave me negative %.

Also, my total at the end won't display anything. At first, I had it and all the function defined in the main(), but it didn't do anything. Even after the change, it doesn't work. Also, last thing, my file has 20 items, yet the loops only read in 19 items. If I change to 20, it crashes.

#include <iostream>
#include <fstream>
#include <string>

using namespace std;

void inputValues(string names[], int votes[])
{

ifstream inputfile;

inputfile.open("votedata.txt");

if(inputfile.is_open())
{
for(int i = 0; i < 19; i++)
{
inputfile >> names[i] >> votes[i];
}
}
}

double *calcPercents( double percents[], int votes[], double total)
{
for(int i = 0; i < 19; i++)
{
percents[i] = votes[i];

total += percents[i];

percents[i] = (percents[i]/total)*100;
}

return percents;
}

string determineWinner(string names[], double percents[])
{
double temp = 0;
string winner;
for(int i = 0; i < 19; i++)
{
if(percents[i] > temp)
{
temp = percents[i];
winner = names[i];
}
}
return winner;
}

void displayResults(string names[], int votes[], double percents[])
{
int total = 0;
calcPercents(percents, votes, total);
cout << "Candidate Votes Received % of Total Votes " << endl;
for(int i = 0; i < 19; i++)
{
cout << names[i] << " " << votes[i] << " " << percents[i] << "%" << endl;
}
cout << "Total " << total << endl;

cout << " The winner of the election is " << determineWinner(names, percents) << endl;

}

int main()
{
string names[19], winner;
int votes[19];
double percents[19];

inputValues(names, votes);
displayResults(names, votes, percents);
}


My file is in the style:

bob (tab) 1254

joe (tab) 768


etc.

Answer

If you have to use arrays instead of std::vectors you should pass their size to the functions using them. One way is to set the size using a constant, like this:

#include <iostream>
#include <fstream>
#include <string>

using namespace std;  // bad practice

const int size = 20;

void inputValues(string names[], int votes[], int n);
// add the size as a parameter of the function ^^^^

int calcPercents( double percents[], int votes[], int n );
//^^ I'll explain later why I changed your signature ^^^

string determineWinner(string names[], double percents[], int n );
void displayResults(string names[], int votes[], double percents[], int n);

int main()
{
    // It's always better to initialize the variables to avoid undefined behavior
    // like the negative percentages you have noticed
    string names[size] ="";
    int votes[size] = {0};
    double percents[size] = {0.0};

    inputValues(names, votes, size);
    displayResults(names, votes, percents, size);
}

To calculate the percentages you can use two loops, one for the sum and the other to get the percentage. In your function you pass total as a parameter by value, so it will be copied and the changes will never be visible outside the function. I choose to return that vaule, even if doing so the name of function becomes a litle misleading:

int calcPercents( double percents[], int votes[], int n )
{
    int total = 0;
    for(int i = 0; i < n; i++)
    // note the bound ^^^
    {
        total += votes[i];
    }
    double factor = 100.0 / total;
    for(int i = 0; i < n; i++)
    {
        percents[i] = factor * votes[i];
    }
    return total;
}

You should also add some checks to the input function, I only add the size parameter. Note that having initialized the arrays, even if it fails reading the file the arrays doesn't contain random values:

void inputValues(string names[], int votes[], int n)
{

    ifstream inputfile;

    inputfile.open("votedata.txt");

    if(inputfile.is_open())
    {
        for(int i = 0; i < n; i++)
        {
            inputfile >> names[i] >> votes[i];
        }
    }
}

I'd change the function which determine the winner too:

string determineWinner(string names[], double percents[], int n )
{
    if ( !n ) 
    {
        return "";
    }
    double max = percents[0];
    // update an index instead of a string
    int winner = 0;              
    for( int i = 1; i < n; i++ )
    {
        if( percents[i] > max )
        {
            max = percents[i];
            winner = i;
        }
    }
    return names[winner];
}

For the last function, only remember to add the size:

void displayResults(string names[], int votes[], double percents[], int n)
{
    int total = calcPercents(percents, votes, n);
    cout << "Candidate  Votes Received  % of Total Votes " << endl; 
    for( int i = 0; i < n; i++ )
    {
        cout << names[i] << "       " << votes[i] << "      "
             << percents[i] << "%" << endl;
    }
    cout << "Total " << total << endl;

    cout << " The winner of the election is "
         << determineWinner(names, percents,n) << endl;    
}