Hey lsu420luv,
Sorry for the reply like 8 hours later. You see, I live in Singapore and the reply you gave was at 4am SGT. Was asleep by then.
From what I saw in your previous post, I think you still do not comprehend quite a number of the C++ concepts... Here's what I did together with an explanation:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
// Const Fields
const int MAXMEMBERS = 20;
const int MAXJUDGES = 5;
// Globals
int pianoPlayer[MAXMEMBERS];
double score[MAXMEMBERS][MAXJUDGES];
double weightFactor[MAXMEMBERS];
int profLevel[MAXMEMBERS];
int judgeNumber[MAXMEMBERS][MAXJUDGES];
double average[MAXMEMBERS];
int weightedScore[MAXMEMBERS];
int category; //category of music the students are playing
int judgeCount[MAXMEMBERS];
int numPlayers;
// Methods
int ReadScores(ifstream& fin);
void PrintReport(ofstream& fout);
void ProcessScores();
Ok, I've separated the globals, constants and methods. You should do that too. It makes reading them a lot easier.
Notice that I have also reduced your PrintReport
method that it only takes in an ofstream
as its parameter. Remember what I told you about global variables? Since all the variables required by PrintReport
are global (i.e. declared outside of any method), you can access them without passing them as parameters into the method.
int main()
{
ifstream fin("PianoREV.data");
ofstream fout("Report.out");
if (!fin)
{
cout << "Error: Input File";
return 1;
}
if (!fout)
{
cout << "Error: Output File";
return 1;
}
numPlayers = ReadScores(fin);
ProcessScores();
PrintReport(fout);
fin.close();
fout.close();
}
Look at how I've reduced your file I/O code. You can simply open an ifstream
or ofstream
by calling their constructors; in other words, just by doing this:
ifstream fin("PianoREV.data");
ofstream fout("Report.out");
After that, you can check if the open succeeded simply by:
if (!fin)
{
cout << "Error: Input File";
return 1;
}
if (!fout)
{
cout << "Error: Output File";
return 1;
}
Basically, putting a stream as the condition of an if
statement tells you if it is still valid. Doing this:
if (!fin)
Is (sort of) the same as:
if (fin.fail())
It's just much shorter. Why "sort of"? I will explain this later.
These are also present in the ReadScores
method, the one that you've been using (underlined):
int ReadScores (ifstream& fin)
{
int i= 0;
int j= 0;
fin >> category;
for (i = 0; fin && i < MAXMEMBERS; ++i)
{
if (!(fin >> pianoPlayer[i]))
break;
if (!(fin >> profLevel[i]))
break;
if (!(fin >> weightFactor[i]))
break;
// Process the judges
for (int j = 0; fin; ++j)
{
if (j >= MAXJUDGES) // If we have too many judges
{
// If the number of judges overflow the array size,
// we have to clear off the remaining judge entries
// so that we can continue reading from the next
// player entry
int k;
if (!(fin >> k) || k == -1)
{
judgeCount[i] = MAXJUDGES; // Set judgeCount to limit
break;
}
else
continue;
}
if (!(fin >> judgeNumber[i][j]) || judgeNumber[i][j] == -1)
{
judgeCount[i] = j;
break;
}
if (!(fin >> score[i][j]))
{
judgeCount[i] = j;
break;
}
}
}
return i;
}
If the input (>>
) and output (<<
) operators makes it look confusing, think of them as methods, and that these methods return the stream you call them with. What does this mean? Whenever you do something like:
cout << "Bob" << 123 << "Tom" << endl;
First of all, the stream you work with now is cout
.
You use the output operator (<<
) on cout
.
And with the output operator, you tell cout
to print "Bob"
, 123
, "Tom"
and endl
(I'll explain endl
later) Understood so far?
What I mean when that these operators are like methods and the return the stream you call them with, means that I call a method something like this happens when I use <<
(C++ pros, don't flame me with this, it's just an abstraction for explanation):
ostream& << (ostream& s)
{
// Some logic ...
return s;
}
Don't get it? Basically, this:
cout << "Bob" << 123 << "Tom" << endl;
Is exactly the same as:
cout << "Bob"; cout << 123; cout << "Tom"; cout << endl;
What does all these mean to you? Basically (look carefully at where the exclamation mark goes):
if (!(fin >> pianoPlayer[i]))
break;
Is exactly the same as:
fin >> pianoPlayer[i];
if (!fin)
break;
Which is also (sort of) the same as:
fin >> pianoPlayer[i];
if (fin.fail())
break;
Why "sort of the same"? Because (look, no exclamation mark):
if (fin)
Is actually doing this:
if (fin.good())
(And of course, if (!fin)
the same as if (!fin.good())
, the NOT operator (!
) just changes true
to false
and vice versa).
It's sort of the same, because fin.good()
is not just the opposite of fin.fail()
! It's also the opposite of fin.eof()
and fin.bad()
. What are these?
fin.eof()
returnstrue
if the End-Of-File (EOF) has been reached.fin.fail()
returnstrue
if some I/O error occurred.fin.bad()
returnstrue
if some fatal I/O error occurred.
So, by using if (!fin.good())
, or simply if (!fin)
checks for all these possible errors.
Now, what is endl
? endl
is the C++ representation of a newline. You should not use "\n"
because this is quite restricted as different OSes use different line terminators. *nix will use "\n"
but Windows "\r\n"
. In order to make your code compile without being OS specific, you should use endl
.
I've used endl
in your PrintReport
method too (underlined):
void PrintReport (ofstream& fout)
{
for (int i = 0; i < numPlayers; ++i)
{
fout << "Piano Player: " << pianoPlayer[i] << endl;
for (int j = 0; j < judgeCount[i]; ++j)
{
fout << "Judge Number: " << judgeNumber[i][j] << " "
<< "Score: " << score[i][j] << endl;
}
fout << "Average Score: " << average[i] << endl
<< "Weighted Score: " << weightedScore[i] << endl << endl;
}
}
You were asking why your PrintReport
method print every player and judge? Look at the changes (underlined):
void PrintReport (ofstream& fout)
{
for (int i = 0; i < numPlayers; ++i)
{
fout << "Piano Player: " << pianoPlayer[i] << endl;
for (int j = 0; j < judgeCount[i]; ++j)
{
fout << "Judge Number: " << judgeNumber[i][j] << " "
<< "Score: " << score[i][j] << endl;
}
fout << "Average Score: " << average[i] << endl
<< "Weighted Score: " << weightedScore[i] << endl << endl;
}
}
You used MAXMEMBERS
and MAXJUDGES
earlier, and that's why you print to MAXMEMBERS
and MAXJUDGES
! It's that simple a logic error. Since you said you wanted a judgeCount
array, I've included it in too. Notice that this is also reflected in the ReadScores
method; ReadScores
will determine how many judges are there per student (underlined):
int ReadScores (ifstream& fin)
{
int i= 0;
int j= 0;
fin >> category;
for (i = 0; fin && i < MAXMEMBERS; ++i)
{
if (!(fin >> pianoPlayer[i]))
break;
if (!(fin >> profLevel[i]))
break;
if (!(fin >> weightFactor[i]))
break;
// Process the judges
for (int j = 0; fin; ++j)
{
if (j >= MAXJUDGES) // If we have too many judges
{
// If the number of judges overflow the array size,
// we have to clear off the remaining judge entries
// so that we can continue reading from the next
// player entry
int k;
if (!(fin >> k) || k == -1)
{
judgeCount[i] = MAXJUDGES; // Set judgeCount to limit
break;
}
else
continue;
}
if (!(fin >> judgeNumber[i][j]) || judgeNumber[i][j] == -1)
{
judgeCount[i] = j;
break;
}
if (!(fin >> score[i][j]))
{
judgeCount[i] = j;
break;
}
}
}
return i;
}
In case that you do not know what break
and continue
is, break
terminates the innermost loop and continues immediately on the code outside the loop. continue
forces the loop to reiterate and evaluate the condition immediately, not executing the remaining code before a normal iteration.
As for ProcessScores
, I've also changed it to use judgeCount
. Other than that, nothing else is changed. I was unable to find any fault with the logic.
void ProcessScores ()
{
int j;
double totalScore;
for (int i = 0; i < numPlayers; ++i)
{
for (j = 0, totalScore = 0; j < judgeCount[i]; ++j)
{
totalScore += score[i][j];
}
if (j != 0)
average[i] = totalScore / j;
weightedScore[i] = average[i] * weightFactor[i];
}
}
Putting everything together, here is the full source code:
#include <iostream>
#include <fstream>
#include <cstdlib>
using namespace std;
// Const Fields
const int MAXMEMBERS = 20;
const int MAXJUDGES = 5;
// Globals
int pianoPlayer[MAXMEMBERS];
double score[MAXMEMBERS][MAXJUDGES];
double weightFactor[MAXMEMBERS];
int profLevel[MAXMEMBERS];
int judgeNumber[MAXMEMBERS][MAXJUDGES];
double average[MAXMEMBERS];
int weightedScore[MAXMEMBERS];
int category; //category of music the students are playing
int judgeCount[MAXMEMBERS];
int numPlayers;
// Methods
int ReadScores(ifstream& fin);
void PrintReport(ofstream& fout);
void ProcessScores();
int main()
{
ifstream fin("PianoREV.data");
ofstream fout("Report.out");
if (!fin)
{
cout << "Error: Input File";
return 1;
}
if (!fout)
{
cout << "Error: Output File";
return 1;
}
numPlayers = ReadScores(fin);
ProcessScores();
PrintReport(fout);
fin.close();
fout.close();
}
int ReadScores (ifstream& fin)
{
int i= 0;
int j= 0;
fin >> category;
for (i = 0; fin && i < MAXMEMBERS; ++i)
{
if (!(fin >> pianoPlayer[i]))
break;
if (!(fin >> profLevel[i]))
break;
if (!(fin >> weightFactor[i]))
break;
// Process the judges
for (int j = 0; fin; ++j)
{
if (j >= MAXJUDGES) // If we have too many judges
{
// If the number of judges overflow the array size,
// we have to clear off the remaining judge entries
// so that we can continue reading from the next
// player entry
int k;
if (!(fin >> k) || k == -1)
{
judgeCount[i] = MAXJUDGES; // Set judgeCount to limit
break;
}
else
continue;
}
if (!(fin >> judgeNumber[i][j]) || judgeNumber[i][j] == -1)
{
judgeCount[i] = j;
break;
}
if (!(fin >> score[i][j]))
{
judgeCount[i] = j;
break;
}
}
}
return i;
}
void ProcessScores ()
{
int j;
double totalScore;
for (int i = 0; i < numPlayers; ++i)
{
for (j = 0, totalScore = 0; j < judgeCount[i]; ++j)
{
totalScore += score[i][j];
}
if (j != 0)
average[i] = totalScore / j;
weightedScore[i] = average[i] * weightFactor[i];
}
}
void PrintReport (ofstream& fout)
{
for (int i = 0; i < numPlayers; ++i)
{
fout << "Piano Player: " << pianoPlayer[i] << endl;
for (int j = 0; j < judgeCount[i]; ++j)
{
fout << "Judge Number: " << judgeNumber[i][j] << " "
<< "Score: " << score[i][j] << endl;
}
fout << "Average Score: " << average[i] << endl
<< "Weighted Score: " << weightedScore[i] << endl << endl;
}
}
Ok, I admit, all the help I gave you thus far are all done without the use of a compiler. I wasn't able to get my C++ compiler up but I can give you the guarantee that the code works. It should. Unless I make some careless mistake, which I believe I didn't.
I would recommend two books if you intend to go into C++:
- C++: The Complete Reference, 4th Edition by Herbert Schildt
- The C++ Standard Library: A Tutorial and Reference by Nicolai M. Josuttis
The first is an extremely good guide and reference (though it states only reference). I would dare to give you my fullest support that this book is the definite reference to C++ (and some C too). It even goes through some more advanced topics like the Standard Library and RTTI. The same author has written many other good books on C++, C and Java as well.
The second is also a must-have for every C++ programmer. The Standard Library is the equivalent of the Java API for C++ (though not as extensive), and no other book gives a tutorial and reference on it as worth as Mr. Josuttis'.
It's sometimes hard to find a good reference on the Internet (which is surprising), so I had to rely on these books for C++ help. In fact, these two books propelled me into programming C++.
You can also check out How Not to Program in C++ by Steve Oualline. It's a rather light-hearted good read on the common mistakes people make with C++.
I believe all's done and you can submit your work. It's been nice working with ya on this, and if there's anything else that needs to be done, don't hesitate to post it. I've sent the PM. Thanks again!