Hello SITHESH,
Sorry this too me longer than I first thought. I had trouble keeping track os some of the variable names because they are so close.
This is what I came up with for the header file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
|
//
// Created by Sithe on 6/2/2021.
//
//#include <iostream>
//#include <string>
//#include <vector>
#ifndef HIGH_SCORE_H // <--- Added.
#define HIGH_SCORE_H
struct High_score;
using HIGH_SCORE_LIST = std::vector<High_score>; // <--- Changed.
struct High_score // <--- Changed.
{
std::string first_name, last_name;
int score;
/*friend std::ostream& operator<<(std::ostream&, const high_score&);
friend std::istream& operator>>(std::istream& ifs, high_score& hs)*/;
void add_high_score(HIGH_SCORE_LIST& hs_list, const std::string&, const std::string&, int);
void writeToFile(const HIGH_SCORE_LIST& hs_list);
static void do_sort(HIGH_SCORE_LIST&);
void do_print(const HIGH_SCORE_LIST&, std::ostream& stm);
void LoadHS(std::ifstream& ifs, HIGH_SCORE_LIST &);
};
#endif // !HIGH_SCORE_H
|
With the using statement and since you are defining a user variable the capital letters do help.
For a class or struct the name works better when you start it with a capital letter. It also helps with functions.
I did this for "main":
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
int main()
{
const std::string inFileName{ "Scores.txt" }; // <--- Put File name here.
std::ifstream inFile(inFileName);
if (!inFile)
{
std::cout << "\n File " << std::quoted(inFileName) << " did not open.\n"; // <--- Requires header file "<iomanip>".
//std::cout << "\n File \"" << inFileName << "\" did not open.\n";
return 1;
}
HIGH_SCORE_LIST scores;
High_score highS;
highS.LoadHS(inFile, scores);
highS.add_high_score(scores, "abc", "def", 22);
highS.add_high_score(scores, "pqr", "xyz", 101);
highS.do_print(scores);
highS.writeToFile(scores);
//highS.do_print(scores);
return 0; // <--- Not required, but makes a good break point for testing.
}
|
Setting up the input file first if there is a problem you leave the program before you get into anything else. Also when you open the output file stream you should check it and not just count on it working.
The problem starts with line 19. Not that the function call is a problem, but the function.
Once you call the "LoadHS" function, your code:
1 2 3 4 5 6 7
|
void high_score::LoadHS(std::ifstream& ifs, HIGH_SCORE_LIST& hs)
{
high_score qz;
while (ifs >> qz)
std::cout << qz.last_name;
hs.emplace_back(qz);
}
|
The while loop is partly correct. line 6 needs to be part of the while loop not by its-self.
The next problem comes when the while condition uses the overloaded extraction operator, (>>), and that function, You have:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
std::istream& operator>>(std::istream& ifs, high_score& hs)
{
std::string word;
if (ifs)
{
while (ifs >> word)
{
std::cout << word + " \n ";
ifs >> hs.first_name >> hs.last_name >> hs.score;
}
}
return ifs;
}
|
Since the file stream has already been opened and checked in "main" you can do without the if statement.The while loop is reading the whole file and line 13 only returns the last read. This function should read only 1 line at a time and return it back to the "LoadHS" function to process.
I ended up with:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
|
std::istream& operator>>(std::istream& ifs, High_score& hs)
{
std::string rank;
ifs >> rank >> hs.first_name >> hs.last_name >> hs.score;
std::cout << "\n " << rank << ' ';
return ifs;
}
void High_score::LoadHS(std::ifstream& ifs, HIGH_SCORE_LIST& hs)
{
High_score tempHighScore;
while (ifs >> tempHighScore)
{
std::cout << tempHighScore.last_name;
hs.emplace_back(tempHighScore);
}
//std::cout << '\n'; // <--- Used as a break point for testing.
}
|
I have not changed it yet, but the "emplace_back" in line 20 can be a "push_back" because you already have an object of the struct constructed and ready to use.
You will notice that I have changed some of the variable names to make it easier to follow.
The "print" function works well and sorts a copy of the vector before it prints it out.
In the "writeToFile" I had a problem with the sort until I changed it to work like the "print" function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
void High_score::writeToFile(const HIGH_SCORE_LIST& hs_list)
{
std::ofstream outputFile;
outputFile.open("users.txt"/*, std::ios::app*/);
// <--- How do you know its open without checking?
High_score high_scores;
//const auto do_sort(hs_list);
auto hs_list_cpy = hs_list; // make a copy
do_sort(hs_list_cpy); // sort the copy
for (size_t idx = 0; idx < hs_list.size(); ++idx)
{
high_scores = hs_list[idx]; // <--- The for loop eliminates the need for "at()".
outputFile << (idx + 1) << " " << hs_list_cpy[idx];
/*outputFile << (idx + 1) << " " << high_scores.first_name << " " << high_scores.last_name << " " << high_scores.score << std::endl;*/
}
}
|
You wrote a function to overload the insertion operator, (<<), but never use it. Line 18 makes use of the overloaded (<<) operator.
Lastly I did this with the include files:
1 2 3 4 5 6 7 8 9
|
#include <iostream>
#include <iomanip> // <--- Added.
#include <string>
#include <vector>
#include <algorithm>
#include <fstream>
#include "high_scores.h"
|
Andy