Unfortunately your approach, or your design idea is not that good. It should be improved a little bit.
You need to start thinking in an object-oriented way. The object "student" has properties or data elements, like "name", "id", "age" and "number". All this data belong together and are related to a specific "student". And next, you need to define methods that should operate on this data, like "reading" and "writing" the complete data for some student.
If the "number" property that you have, after reading a complete "student" record, is ok, then you will store it in some kind of array or std::vector
So, lets start with the data part:
struct Student {
std::string name{};
unsigned long id{};
unsigned int age{};
unsigned int number{};
};
This will describe the properties of one student.
Next, we do want to operate on this data. And the first operation is that we do want to read this data from any kind of stream
, for example from the console (std::cin
) or from a file (std::ifstream
). This basically doesn't matter, stream is stream :-)
The iostream library has the so called "extractor" operator for reading from streams. That is the >>
operator. And this we can simply define for our "Student" struct. Like so:
friend std::istream& operator >> (std::istream& is, Student& s) {
return std::getline(is >> std::ws, s.name) >> s.id >> s.age >> s.number;
}
The signature of the function is given. This is a formal requirement. Then, now to what are we doing in that function. I would like to remind everybody that the istream
extraction operations always return a reference to the given istream.
. So, first we call std::getline
. This will read the name of the student, and then return again is. Then the line looks like return is >> s.id >> s.age >> s.number
. Next we will read the id. This will also return is. Then the statement would look like return is >> s.age >> s.number
. And so on and so on. At the end we will have read everything and simply return is;
In the std::getline
you will see >>std::ws
. This will ignore all leading white spaces like new lines or whatever.
So, now, if we have an open file stream, let' s say "ifs" and a Student variable called "student", then we can write ifs >> student
and it will read a complete student record from the file. So, all 4 lines.
By the way, we can do the same mechanism for the inserter function <<
.
If we run this in a loop now and store the read student data into a std::vector
we can copy all data from the file.
Or, if a student has a certain property, then we can also decide to not copy the data.
This could then look like:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
struct Student {
std::string name{};
unsigned long id{};
unsigned int age{};
unsigned int number{};
friend std::istream& operator >> (std::istream& is, Student& s) {
return std::getline(is >> std::ws, s.name) >> s.id >> s.age >> s.number;
}
friend std::ostream& operator << (std::ostream& os, const Student& s) {
return os << s.name << '
' << s.id << '
' << s.age << '
' << s.number << '
';
}
};
int main() {
// Here we will store all our studends
std::vector<Student> students{};
// Open the file with the data
std::ifstream ifs("r:\data.txt");
// Check, if the file could be opened.
if (ifs) {
Student tempStudent{};
// Read all students from a file, until we hit eof or some other problem
while (ifs >> tempStudent) {
// if the student does fullfill the requirements, then we take it, else not
if (tempStudent.number != 2)
students.emplace_back(std::move(tempStudent));
}
// OK, for debug purposes we show all data ion the screen
for (const Student& s : students) std::cout << s << '
';
}
else std::cerr << "
Error: source file could not be opened
";
return 0;
}
And if you want to see a more advance C++ solution, please look at the below:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <iterator>
#include <algorithm>
struct Student {
std::string name{};
unsigned long id{};
unsigned int age{};
unsigned int number{};
friend std::istream& operator >> (std::istream& is, Student& s) {
return std::getline(is >> std::ws, s.name) >> s.id >> s.age >> s.number;
}
friend std::ostream& operator << (std::ostream& os, const Student& s) {
return os << s.name << '
' << s.id << '
' << s.age << '
' << s.number << '
';
}
};
int main() {
// Here we will store all our studends
std::vector<Student> students{};
// Open the file with the data and check, if it is open
if (std::ifstream ifs("r:\data.txt");ifs) {
// Read all data
std::copy_if(std::istream_iterator<Student>(ifs), {}, std::back_inserter(students), [](const Student& s) {return s.number != 2;});
// For debug purposes we show all data ion the screen
std::copy(students.begin(), students.end(), std::ostream_iterator<Student>(std::cout, "
"));
}
else std::cerr << "
Error: source file could not be opened
";
return 0;
}