-3

I need to find the row in an array that has the largest average temperature. There two main variables, one that indicates how many days have temperature measurements and another that indicates how many measurements were taken each day. Fortunately, in most cases I have tried, the program does indicate the correct day with the largest average temperature. However, in some cases, such as the following, it does not work and I cannot figure out why.

If I insert the following values:

4 3

8 8 10

12 10 7

14 12 11

11 10 12

It should display a 2, since it is the day with the largest average temperature. However, for some reason, it instead displays a 0.

Here's the code I am using:

include <iostream>
using namespace std;

void largestaverage (int array[100][100], int amountDays, int amountMeasurements, int &largest, int &largestDay, int dailyAverage)
{
 largest=array[0][0];
 largestDay=0;
 for(int i=0; i<amountDays; i++)
 {
    dailyAverage=0;
     for(int k=0; k<amountMeasurements; k++)
     {
        dailyAverage+=array[i][k];
        dailyAverage=dailyAverage/amountMeasurements;
        if(dailyAverage>largest)
        {
           largest=array[i][k];
           largestDay=i;
        }
     }
  }
}

int main ()
{
 int array[100][100], amountDays, amountMeasurements, largest, largestDay, dailyAverage=0;
 cin>>amountDays;
 cin>>amountMeasurements;
 for (int i=0; i<amountDays; i++)
 {
     for (int k=0; k<amountMeasurements; k++)
     {
         cin>>array[i][k];
     }
 } 
 largestaverage (array, amountDays, amountMeasurements, largest, largestDay, dailyAverage);
 cout<<largestDay<<endl;
 return 0;
}
John Smith
  • 11
  • 2
  • 3
    Now seems like the perfect time to [learn how to debug your programs](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). – Some programmer dude Nov 09 '18 at 07:26
  • A possible hint though: Your calculation of the average for the days look *very* suspect. The average should be calculated *after* the inner loop, when you have the total sum. – Some programmer dude Nov 09 '18 at 07:28
  • Also why are you initialising `largest` like this? what if `array[0][0]` contains some extremely large value, larger than any daily average? – Tomek Szpakowicz Nov 09 '18 at 07:30

2 Answers2

1

John, it's obvious you are struggling a bit with understanding what values you need to pass as parameters to your function and how to handle the loops to obtain the largest daily average based on your data.

To begin, the only parameters that need to be passed to largestaverage() are the array itself, and the bounds indicating the number of days and measurements taken for each day. From that information alone you can compute the largest daily average -- but how to get that largest daily average back to main() so it can be used?

The key is to pick a meaningful return type for your function so that you can return the needed information. Since you are validating the data you read into array in main() (aren't you?), there is little need to choose a return type to indicate success/failure of the calculation, but choosing void provides no benefit at all and you are left to pass a reference.

While this will work, there is a much more fundamental way to handle the return -- just return a value to main() of the needed type. That eliminates the need to pass largest at all. A function can always return its own type. But, what type? double makes a fine choice, since the result of the division of the sum with the number of measurements will result in a floating-point value -- unless you intend integer division to occur.

Making the change to the return type for largestaverage, and rearranging the loops so that the sum and avg are computed on a daily basis and properly re-initialized for the next day, and including <limits> so that you can use a standard way to initialize largest to the smallest value available for your type, you could do something similar to:

...
#include <limits>   /* for numeric_limits */
...
#define MAXDM 100   /* if you need a constant, #define one (or more) */

/* choose a meaningful return type, and return a value */
double largestaverage (int array[][MAXDM], int days, int msrmts)
{
    /* initialize largest sufficiently small (all vals could be negative) */
    double largest = std::numeric_limits<double>::min();

    for (int i = 0; i < days; i++) {        /* loop over each day */
        int sum = 0;                        /* initialize sum/avg */
        double avg = 0;
        for (int k = 0; k < msrmts; k++)    /* loop over measurements */
            sum += array[i][k];             /* compute sum */
        avg = sum / (double)msrmts;         /* compute avg */
        if (avg > largest)                  /* check against largest */
            largest = avg;
    }
    return largest;                         /* return largest */
}

Rearranging main() and adding the needed validations for every input, you could do something similar to the following:

int main (void) {

    int array[MAXDM][MAXDM] = {{0}},    /* declare/initialize variables */
        days, measurements;

    if (!(cin >> days >> measurements)) {   /* VALIDATE read of input */
        cerr << "error: invalid format for days/measurements\n";
        return 1;
    }
    for (int i = 0; i < days; i++)          /* loop over days */
        for (int k = 0; k < measurements; k++)  /* loop over measurements */
            if (!(cin>>array[i][k])) {      /* VALIDATE read of input */
                cerr << "error: invalid format row '" << k + 1 << "'\n";
                return 1;
            }

    /* output results */
    cout << "largest daily avg: " 
        << largestaverage (array, days, measurements) << endl;
}

Putting it altogether in a short example, would result in:

#include <iostream>
#include <limits>   /* for numeric_limits */

using namespace std;

#define MAXDM 100   /* if you need a constant, #define one (or more) */

/* choose a meaningful return type, and return a value */
double largestaverage (int array[][MAXDM], int days, int msrmts)
{
    /* initialize largest sufficiently small (all vals could be negative) */
    double largest = std::numeric_limits<double>::min();

    for (int i = 0; i < days; i++) {        /* loop over each day */
        int sum = 0;                        /* initialize sum/avg */
        double avg = 0;
        for (int k = 0; k < msrmts; k++)    /* loop over measurements */
            sum += array[i][k];             /* compute sum */
        avg = sum / (double)msrmts;         /* compute avg */
        if (avg > largest)                  /* check against largest */
            largest = avg;
    }
    return largest;                         /* return largest */
}

int main (void) {

    int array[MAXDM][MAXDM] = {{0}},    /* declare/initialize variables */
        days, measurements;

    if (!(cin >> days >> measurements)) {   /* VALIDATE read of input */
        cerr << "error: invalid format for days/measurements\n";
        return 1;
    }
    for (int i = 0; i < days; i++)          /* loop over days */
        for (int k = 0; k < measurements; k++)  /* loop over measurements */
            if (!(cin>>array[i][k])) {      /* VALIDATE read of input */
                cerr << "error: invalid format row '" << k + 1 << "'\n";
                return 1;
            }

    /* output results */
    cout << "largest daily avg: " 
        << largestaverage (array, days, measurements) << endl;
}

Example Input

$ cat file
4 3
8 8 10
12 10 7
14 12 11
11 10 12

Example Use/Output

$ ./bin/dailyavg < file
largest daily avg: 12.3333

The largest average corresponding to the third days input.

Letting C++ Do Most Of The Work

While there is absolutely nothing wrong with using basic array types and manual for loops in C++, for all practical purposes, your code, and the code above is nothing but standard C aside from using cin/cout instead of scanf/printf and using numeric_limits<double>::min() instead of DBL_MIN.

The reason we have C++ is to make things easier. Instead of int array[100][100] declaring an integer array with automatic storage duration, and fixed bounds of 100 arrays of 100 int each, you could instead use vector<vector<int>> array; and let C++ handle the bounds and memory management for you. Rather than loop over some fixed bounds, you simply use an auto range for loop (C++ 11) to loop over what is filled. (this also eliminates the need to pass the bounds to your function, instead simply pass a reference to array).

Rather than inner and outer loops summing and computing each daily average, you can simply loop over the daily data using accumulate to sum each days values and then simply dividing by the .size() of the daily vector.

Letting C++ do most of the work for you reduces the amount of manual looping, summing and averaging required, e.g.

#include <iostream>
#include <vector>   /* for vector */
#include <numeric>  /* for accumulate */
#include <limits>   /* for numeric_limits */

using namespace std;

/* choose a meaningful return type, and return a value */
double largestaverage (vector<vector<int>>& array)
{
    /* initialize largest sufficiently small (all vals could be negative) */
    double largest = std::numeric_limits<double>::min();

    for (auto day : array) {            /* loop over each day vector */
        double avg = accumulate (day.begin(), day.end(), 0) / 
                    static_cast <double>(day.size()); /* compute avg */
        if (avg > largest)              /* check against largest */
            largest = avg;
    }
    return largest;                     /* return largest */
}

int main (void) {

    vector<vector<int>> array;          /* declare vector of vectors */
    int days, measurements;

    if (!(cin >> days >> measurements)) {   /* VALIDATE read of input */
        cerr << "error: invalid format for days/measurements\n";
        return 1;
    }
    for (int i = 0; i < days; i++) {        /* loop over days */
        vector<int> tmp;
        for (int k = 0; k < measurements; k++) { /* loop over measurements */
            int msrmt;
            if (!(cin >> msrmt)) {      /* VALIDATE read of input */
                cerr << "error: invalid format row '" << k + 1 << "'\n";
                return 1;
            }
            tmp.push_back(msrmt);       /* add msrmt to tmp vector */
        }
        array.push_back(tmp);           /* add tmp vector to array */
    }
    /* output results */
    cout << "largest daily avg: " << largestaverage(array) << endl;
}

(you could even eliminate the need to read the first row of your data file and simply read the days as a string with getline and the create a stringstream and loop with >> to an int to .push_back())

Both approaches are fine, the first is just basically C and there is nothing wrong with it, the second utilizes some of the niceties of C++. Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
0

Set the largest to the largest average value you see instead of largest=array[i][k].

if(dailyAverage>largest)
{
   largest=dailyAverage;
   largestDay=i;
}

Also, like "@Some programmer dude" mentioned, best would be to calculate the average outside the loop.

Edit: Initialize your largest to an impossibly small number as it will very likely cause a logical error.

largest=-1000;
Sharath
  • 216
  • 2
  • 11
  • There will not be a type mismatch here. `array[0][0]` is an int and `largest` is passed by reference as `int` not `int*`. But this can cause a logical error. Ideally, largest should be initialised to significant small number like -1000 or so. – Sharath Nov 09 '18 at 08:05