The OP does not want to change the file, so this answer is no longer suitable. Work in progress.
There are two broad strategies here
We can choose to:
- Have the user format the data for us.
- Have the program format the data.
And then we parse it.
1) Fixed data format:
The easiest solution.
Make the user enter data in a format that can easily be parsed. Here, it is up to the user to enter the data correctly, and program will check if the data entered is correct. This can be done in many ways, including, but not in entirety:
Peter-Richmond Barker 1234 5678 // hyphen(-) separated
"James Herbert" Bond 007 999 // enclosed in quotes("")
Barack_Hussein Obama 2007 14165 // underscore(_) separated
In the first and third case, std::cin >> person.first_names
is enough.
In the second case, you would have to
std::getline(std::cin, person.first_names, '\"'); // any character delimiter
it, after checking for the opening delimiter with std::cin.get() == '\"'
.
2) Slow and Steady
Another very easy solution. Just make the user enter one thing at a time:
std::cout << "Enter some datum 1: ";
std::cin >> person.some_datum_1;
...
(Contrary to popular imagination, datum is singular, and data is plural).
For multiple inputs, see line tokenisation:
Let me grab a method here:
std::cout << "Enter some data 1: ";
// Grab the line and put into a stream
std::getline(std::cin, line);
std::stringstream line_buffer(line);
// Prepare to iterate over the stream
std::istream_iterator<std::string> it(line_buffer);
std::istream_iterator<std::string> end;
// Set the name with a move assignment operator
person.first_names = std::move(std::vector<std::string>(it, end));
...
Note that this method will require person.first_names
to be a std::vector<std::string>
.
3) Start from The End
Here, we input the undetermined size data first.
Warning: It will work only for a single undetermined size input. If both the first and last names can be more than two, this wouldn't work. I mention it only for completeness.
If you don't want to coerce the user into this and spoil their experience, you would have to parse the input yourself. Input the whole line with the good old std::getline(std::cin, line);
.
Initialise int read_from = std::string::npos;
.
Now, find the last space with read_from = line.rfind(' ', read_from);
. A read_from == std::string::npos
will tell you that all inputs have been parsed, or there is an error.
A line.substr(read_from)
fetches you the last input. Convert it to the appropriate type and store. You will also have to erase the parsed input with line.resize(read_from);
Rinse and repeat for the other inputs.
Note: It is suggested to store the undetermined data in a std::vector
of the appropriate type.
4) March of Bytes
I know you would say that we have not addressed the OP's question,
... read in a file with personal information...
Now that we have discussed taking the input from the user, we can also choose how to store it (and fetch it).
The easiest way is to:
personal_data_file.write((char*)&person_list[i], sizeof(Person)); // Write it...
personal_data_file.read((char*)&person_list[i], sizeof(Person)); // ...Now read it.
in a loop, where person_list
is a std::vector
of Person
s.
Note: Remember to open the file in std::ios::binary
mode!
Elegant!
But just in case you are not familiar with classes and some features used in the examples above. Here are some links:
std::getline https://www.geeksforgeeks.org/how-to-use-getline-in-c-when-there-are-black-lines-in-input/
std::istream::read http://www.cplusplus.com/reference/istream/istream/read/
std::ostream::write http://www.cplusplus.com/reference/ostream/ostream/write/
std::vector https://www.geeksforgeeks.org/vector-in-cpp-stl/
std::istream_iterator<T> http://www.cplusplus.com/reference/iterator/istream_iterator/