Let me try to help you.
First we will look at your program and comment on it.
using namespace std;
you should not open the complete standard namespace. You will find many many comments here on SO recommending that. So, please omit that line an use qualified names everywhere (like std::string
)
ifstream inputStream1;
inputStream1.open("testAnswers.txt");
You can and should do this in one line. The iostreams have a constructor, taking the filename. Additionally, you should always check the result of any IO operation. This you can simply do with an if (inputStream1)
, because the bool
and the !
-operator for iostreams are overloaded and return the state of stream. And, you should not use hardcoded string literals, please use const std::strings
instead and store the file name. Last, but not least, we will use the if
-statement with initializer to prevent the pollution of the outer name space. You should always try to narrow the scopy of your variable as much as possible. The resulting statement for opening a file will be:
if (std::ifstream correctAnswersStream{ fileNameCorrectAnswers }; correctAnswersStream) {
Another big advantage is that the iostreams destructor will close the file automatically for you, when they "fall" out of scope. So, no need for a close
-statement.
Then you define tons of string variables. First strong recommendation: Please always initialize all variables. Use the {}
for default initialization. Ant, if you have many variables with the same meaning, you should put them in a ```std::vector. If you have variables that logically belong together, the put them in a
struct(
class````). for example like:
std::vector<std::string> answer{};
of for a struct something like that:
struct Test {
std::string name{};
std::vector<std::string> answer{};
};
And then you would define methods to operate on your data. At least you could overwrite the inserter (<<
) and the extractor (>>
) operator for simple io operations. Only the class (struc
) should know, how to read write data, not the outer world.
So you could for example add a simple inserter like the belo:
struct Correct {
std::vector<std::string> answer{};
// Overwrite inserter. Show all data
friend std::ostream& operator << (std::ostream& os, const Correct& c) {
std::copy(c.answer.begin(), c.answer.end(), std::ostream_iterator<std::string>(os, " "));
return os;
}
};
Now let's look at you next statement and the main source of your problems:
while(inputStream1 >> name >> a1 >> b1 >> c1 >> d1 >> e1 >> f1 >> g1 >> h1 >> i1 >> j1){
}
You use a while
-loop to read you variables, but, the problem is that you do nothing in the loop body. YOu read the variables, but not store their value in a std::vector
or somehwere else. And then, during the next loop run, all preiviously read values will be overwritten with the new vales and their old content will be lost. And when the loop finishes, you will have the values of the last line in your varaibles, because you have overwritten and discarded all previously read values. That needs to changed.
Store the contents of the variables somewhere.
This you need to do for both input files. Then you can compare verything with everything else.
You will find out that you need somehow a 2 dimensional container. Or, a std::vector
for your own struct
which again contains another std::vector
.
Because I want to help you, but not do your homework, I will add an example program using a little bit more sophisticated coding style. With that you can understand the logic, but most certainly not some of the more advanced stuff.
However, of course the following will work:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iterator>
#include <algorithm>
struct Correct {
std::vector<std::string> answer{};
friend std::istream& operator >> (std::istream& is, Correct& c) {
// Read a complete line and check, if that worked
if (std::string line{}; std::getline(is, line)) {
// Put line into an istringstream for easier extraction
std::istringstream iss(line);
// CLear all old data from vector
c.answer.clear();
// Copy all answers from file into internal vector
std::copy(std::istream_iterator<std::string>(iss), {}, std::back_inserter(c.answer));
}
return is;
}
// Overwrite inserter. Show all data
friend std::ostream& operator << (std::ostream& os, const Correct& c) {
std::copy(c.answer.begin(), c.answer.end(), std::ostream_iterator<std::string>(os, " "));
return os;
}
};
struct Test {
std::string name{};
std::vector<std::string> answer{};
friend std::istream& operator >> (std::istream& is, Test& t) {
// Read a complete line and check, if that worked
if (std::string line{}; std::getline(is, line)) {
// Put line into an istringstream for easier extraction
std::istringstream iss(line);
// Try to extract the name
if (iss >> t.name) {
// Clear all old data from vector
t.answer.clear();
// Copy all answers from file into internal vector
std::copy(std::istream_iterator<std::string>(iss), {}, std::back_inserter(t.answer));
}
}
return is;
}
// Overwrite inserter. Show all data
friend std::ostream& operator << (std::ostream& os, const Test& t) {
std::copy(t.answer.begin(), t.answer.end(), std::ostream_iterator<std::string>(os, " "));
return os;
}
};
const std::string fileNameTestAnswers{ "r:\\testAnswers.txt" };
const std::string fileNameCorrectAnswers{ "r:\\CorrectAnswers.txt" };
const std::string fileNameResult{ "r:\\outputAnswers.txt" };
int main() {
// Open file with test answers and check, if it could be opened
if (std::ifstream testAnswersStream{ fileNameTestAnswers }; testAnswersStream) {
// Open file with correct answers and check, if it could be opened
if (std::ifstream correctAnswersStream{ fileNameCorrectAnswers }; correctAnswersStream) {
// Open file for the resulting output
if (std::ifstream resultAnswersStream{ fileNameCorrectAnswers }; resultAnswersStream) {
// Now all the files are open and we can start. Try to read all files
std::vector<Correct> correct{};
std::vector<Test> test{};
// Read files
std::copy(std::istream_iterator<Correct>(correctAnswersStream), {}, std::back_inserter(correct));
std::copy(std::istream_iterator<Test>(testAnswersStream), {}, std::back_inserter(test));
// Inform user that he has to enter a name
std::cout << "\nPlease enter a name for checking the results:\n";
// Read the name
if (std::string searchName{}; std::getline(std::cin, searchName)) {
// Search the input search name in our test vector
// Goto all tests, because maybe the name is in the file several times
for (auto record{ std::find_if(test.begin(), test.end(), [&searchName](const Test& t) { return t.name == searchName; }) };
record != test.end();
record = std::find_if(std::next(record), test.end(), [&searchName](const Test& t) { return t.name == searchName; })) {
// So go through all the records that contain the search names and compare with all answers
for (const auto& co : correct) {
size_t okCounter{};
for (size_t r{}, c{}; r < record->answer.size() && c < co.answer.size(); ++r, ++c) {
if (record->answer[r] == co.answer[c]) ++okCounter;
}
// Incase there was a match, show result
if (okCounter > 0U)
std::cout << "\nName:\t\t " << searchName << "\nGiven answer:\t " << *record << "\nCorrect answer:\t "
<< co << "\nNumber matches:\t " << okCounter;
std::cout << "\n\n";
}
}
}
else std::cerr << "\n\nError while reading search name files\n\n";
}
else std::cerr << "\n\nError: Could not open file '" << fileNameResult << "'\n\n";
}
else std::cerr << "\n\nError: Could not open file '" << fileNameCorrectAnswers << "'\n\n";
}
else std::cerr << "\n\nError: Could not open file '" << fileNameTestAnswers << "'\n\n";
return 0;
}