Some comments:
Don't write your own sort.
The STL has its own built in sorting algorithms.
All you do is have to specify a relationship between the objects:
bool operator<(student const& lhs,student const& rhs)
{
return lhs.GetName() < rhs.GetName();
}
// Now a sort is:
std::sort(list.begin(),list.end());
Don't use: while (!file.eof())
This is the standard anti-pattern for reading a file.
The problem is that it is either too early or two late for the test. If you have not read anything it is two early as nothing has happened. If you have read something then it is already too late as you have done the processing on the item you read (but failed).
The best way is to put the read into the while loop. This is because the result of the read returns a reference to the stream. This can automatically be converted into an object that can be used in a boolean context (the conversion test to see if something is wrong with the stream). So a read failure will leave the stream in a state that would cause it to be converted into the equivalent of false in a boolean context.
std::string line;
while(std::getline(file,line))
{
// loop only entered if getline() worked.
// Thus we know that we have a good value in line.
// use line
}
Don't use magic numbers:
Are you really ignoring 8000 characters or just trying to drop a line?
file.ignore(8196,'\n');
You have two alternatives:
std::string ignoreLine;
std::getline(file,ignoreLine);
// Dont use a magic number but use a number that is guranteed not to fail.
file.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
Don't be lazy:
The main thing about programming is writing maintainable code.
Using this kind of initialization is (relatively universally) condemned as just lazy. Put each declaration on a separate line. It makes the code easier to read.
string tempname, tempgrade, tempcourse = "";
// Like this:
std::string tempname;
std::string tempgrade;
std::string tempcourse;
Use a stringstream to break the line into parts
I am not sure what you are attempting here?
if (file != "\n")
{ getline(file, tempname, ',');
getline(file, tempcourse, ',');
getline(file, tempgrade, ',');
}
I think it would be easier to read if we combine it with the loop above:
std::string line;
while(std::getline(file,line))
{
std::stringstream linestr(line);
if (getline(linestr, tempname, ',') &&
getline(linestr, tempcourse, ',') &&
getline(linestr, tempgrade, ',')
)
{
// Here we have read a line.
// And successfully retrieved three comma separated values from the line
}
}
When opportunity arises replace a loop with a standard algorithm
This print loop can be replaced by std::copy()
for (int i = 0; i < StudentList.size(); i++)
{ cout << StudentList[i].GetName() << " "
<< StudentList[i].GetCourse() << " "
<< StudentList[i].GetGrade() << endl;
}
All you need to do is define an output operator for your class.
std::ostream& operator<<(std::ostream& str,student const& data)
{
str << data.getName() << " "
<< data.getCourse() << " "
<< data.getGrade() << " "; // No newline here.
return str;
}
Now we can copy the vector to the std::cout
std::copy(StudentList.begin(),StudentList.end(),
std::ostream_iterator<student>(std::cout,"\n")
);
The main bug.
The main bug I see is this line:
if (file != "\n")
Here you compare file against a 'C-string'. How the compiler manages to compile this I am not sure.
Several options spring to mind, but the fact that it is not obvious makes it a likely source of a bugs. Also note this is not how you compare two strings (unless one is a std::string).
I think the compiler will convert a file into a pointer and compare that with the "C-String" (as this is also just a pointer). You may think that is a bit strange but there is an operator that will convert a file into a void*. The pointer does not point at anything meaningful but is either NULL or not NULL and can be compared against a char* pointer thus resulting in a true (as it never equals the string "\n").