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.