Mixing formatted input with unformatted input is always asking for trouble. When you extract input into the stream, a newline is always appended. The newline character is the delimiter for std::getline()
, meaning whilst extraction is being performed, if std::getline()
finds a newline, it discards that character and stops input.
This is the problem you're running into. After the last formatted extraction cin >> input
, the newline is left in the input stream. std::getline()
(unlike formatted input functions) do not discard leading whitespace, so it is prone to the disadvantage I explained above.
To solve this issue, you need to discard leading whitespace manually, so the the non-whitespace input is ready to be extracted by the time std::getline()
is invoked:
std::getline(std::cin >> std::ws, arr[i].name);
// ^^^^^^^^^^^^^^^^^^^
std::ws
is manipulator which extracts and discards leading whitespace. This should be satisfactory for your purposes.
The following are suggestions that I advise you take. They lead to a substantially cleaner, clearer code structure. And it also reduces a lot of headaches:
1. Your class should have its own inserter/extractor.
You should define your own inserter/extractor to encapsulate I/O semantics for your class. It facilitates a lot of the trouble of manual extraction. Inserters/extractors are typically implemented as friend
s of the target class so that it may access private data members. Your class in particular has no private data members, but this is still an idiomatic technique nontheless:
struct info
{
string name;
string address;
int phone;
friend std::ostream& operator<<(std::ostream&, const info&);
friend std::istream& operator>>(std::istream&, info&);
};
Inserters/extractors are global functions because they are being defined in terms of (not only) the target class, but also the stream object itself.
2. Use std::vector<T>
rather than raw C-style arrays
The following is wrong:
cin >> input;
info arr[input];
This code instantiates an array at compile-time with a size known only at runtime. The possibility of your compiler accepting this code fully depends on how standard-conformant it is. GCC has a non-standard extension which welcomes code like that, but it is non-standard even so and shouldn't be used.
If you need an array of objects whose size is known at runtime, use a vector of those objects. A vector class is already provided for you through the Standard library:
std::cin >> input;
std::vector<info> arr(input);
In fact, the size is superfluous since the vector will grow dynamically as more and more elements are created. You can simply default-construct the vector (unless you have a good reason to specify the size, in which case that many info
objects will be default-constructed in the internal buffer of the vector).
std::vector<info> arr;
This is mostly it. Here is an example of your program that applies these two suggestions:
#include <iostream>
#include <vector>
struct info
{
std::string name;
std::string address;
int phone;
friend std::ostream& operator<<(std::ostream&, const info&);
friend std::istream& operator>>(std::istream&, info&);
};
std::ostream& operator<<(std::ostream& os, const info& obj)
{
return os << "Person's name is: " << obj.name << std::endl
<< obj.name << "'s address is: " << obj.address << std::endl
<< obj.name << "'s phone number is: " << obj.phone << std::endl;
}
std::istream& operator>>(std::istream& is, info& obj)
{
std::cout << "Enter name for person " << ": ";
std::getline(is >> std::ws, obj.name);
std::cout << "Enter the address of " << obj.name << std::endl;
std::getline(is >> std::ws, obj.address);
std::cout << "Enter phone number of " << obj.name << std::endl;
std::cin >> obj.phone;
std::cout << endl;
return is;
}
int main()
{
int input;
std::cout << "How many people do you want on the list" << std::endl;
std::cin >> input; // just as a formality, but really the user can enter
// as much as they want.
// The value of input will be ignored.
std::vector<info> arr;
info obj;
while (std::cin >> obj)
{
arr.push_back(obj);
}
for (const auto& item : arr)
std::cout << item << std::endl;
}
If you have any questions, please leave them as a comment and I will try to help you as best as possible.