for loop skipping getline - c++

Hello everyone I am doing a programming assignment on structured data and I believe I understand how structs work.
I am trying to read in a list of student names, ID numbers (A-Numbers), and their balances.
When I compile my code though, it will read everything in the first time around, but the second time around the loop and every time after, it prompts for the username but skips the getline and goes straight to A-Number and A-number entry.
Any help would be appreciated. Just trying to figure out how to make the getline work every time the loop goes around.
#include <iostream>
#include <string>
#include <iomanip>
using namespace std;
int main(){
const int maxStudents = 30;
struct Students{
string studentName;
int aNumber;
double outstandingBalance;};
Students students[maxStudents];
for(int count = 0; count < maxStudents-1; count++)
{
cout<<"Student Name:";
cin.ignore();
getline(cin,students[count].studentName);
cout<<"\nA-Number:";
cin>>students[count].aNumber;
if(students[count].aNumber == -999)
break;
cout<<"\nOutstanding Balance:";
cin>>students[count].outstandingBalance;
}
cout<<setw(20)<<"A-Number"<<"Name"<<"Balance";
for(int count2 = 29; count2 >= maxStudents-1; count2--)
cout<<setw(20)<<students[count2].aNumber<<students[count2].studentName<<students[count2].outstandingBalance;
system("pause");
return 0;
}

Look up C++ FAQ on iostreams.
Item 15.6 specifically deals with your problem ("Why is my program ignoring my input request after the first iteration?"), but you may find the whole page useful.
HTH,

Put
cin.ignore();
at the end of the loop.

The reason what you're doing doesn't work is that the '>>' operators the
first time through don't extract the trailing '\n', the next getline
sees it, and returns immediately with an empty line.
The simple answer is: don't mix getline and >>. If the input is
line oriented, use getline. If you need to parse data in the line
using >>, use the string read by getline to initialize a
std::istringstream, and use >> on it.

The problem is with mixing cin and getline. Formatted input (with the >> operator) and unformatted input (getline is an example) don't play well together. You should definitely read more about it. Click here for more explanation.
Here is the solution to your problem.
cin.ignore(1024, '\n'); is the key.
for(int count = 0; count < maxStudents-1; count++)
{
...
cout<<"\nOutstanding Balance:";
cin>>students[count].outstandingBalance;
cin.ignore(1024, '\n');
}

If you have a problem with the skipping with getline()
Use it like this std::getline(cin>>ws,a);
Using ws will skip the white space.

Related

Reading a row until newline in the console

I need to make a program that reads n numbers in a row. For example, the user first puts in a list of 2 numbers like this:
P n
I managed to read those with scanf but now I need to read the n following numbers, these numbers are given in a row as follows.
1 6 3 99 ... n times
These numbers must be read all at once (or give the impression of).
I already tried using
while(getline(cin,str)){
// do something with str
}
As explained in this thread but I need the actions inside the while loop to stop when I hit the intro key. With my current implementation they don't stop, it just keeps waiting for more lines to read.
In summary:
First, user must be able to input two numbers (P and n)(done!) then hit enter and start typing a list of n numbers (not done!).
Here is my code.
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main(void){
int P,n;
scanf("%d %d",&P,&n);
string val;
int score[P];
int i;
for(i=0;i<P;i++){
score[i]=0;
}
while(getline(cin,val)){
printf("Val=%s\n",val.c_str());
stringstream stream(val);
int local;
while(stream >> local){
score[local]=score[local]+1;
printf("%d-%d\n",local,score[local]);
}
}
for(i=0;i<P;i++){
printf("%d-%d\n",i,score[i]);
}
return 0;
}
Use scanf() inside the n times loop instead of getline().
for(int i = 0; i < n; i ++){
scanf("%d",&variable);
}
Not sure I understood your question, but this code will read 2 numbers, then a line and then finish.
using namespace std;
int main(){
int P,n;
cin >> P;
cin >> n;
int *score = new int[P];
for(int i=0;i<P;i++){
score[i]=0;
}
int num;
string val;
cin.ignore();
getline(cin, val);
istringstream stream(val);
while (stream >> num) {
printf("Val = %d\n", num);
score[num]=score[num]+1; // potential segmentation fault here in your code
printf("%d-%d\n",num,score[num]);
}
delete [] score;
return 0;
}
The fault would occur because you are assuming that the number on the line is smaller than P, which is the size of the array. However, the following input would cause error:
1 2
5
This question is almost a classic. The classic question has this code:
cin >> n;
getline(cin, s);
and then the author is puzzled why s is empty. Your variation does the same, although it also uses C stdio function to make matters more confusing. The problem is that the first call is a field-based input, which will read a single value n and leave any other input in the buffer! If the user entered 42 and hit enter, the remaining input is the newline. The second getline() call then reads an empty string and discards the newline.
For interaction with the user, only use getline() and then try to parse each line. Using stringstreams or sscanf(), since you seem familiar with it, are both valid options. However, if you only want to read the input an not really interact, David Weston's suggestion is also a good one and probably the easiest one, too. However, since you're using C++, I'd suggest using cin >> variable instead.

Reading sentences as string inputs from users

I have been trying to implement a simple code which takes a sentence as an input from the user, stores it in a string and displays it back.
Here are the issues:
1. When T = 1, the program exits immediately.
2. When T>1, the loop runs for only T-1 times.
I think the usage of cin to store the value of T is an issue here. Is the value of T entered being stored as a string due to some buffer capacity of cin?
#include <iostream>
#include <string>
int main()
{
int T;
std::cin >> T;
while (T--)
{
std::string song;
getline(std::cin, song);
std::cout << song << std::endl;
}
return 0;
}
How do you terminate the input that becomes T? With a newline. What happens with that newline after you read into T? It's still left in the input buffer. What will happen when you next call std::getline, what is the first character it will read? The newline, and what happens next? The loop iterates and then T is zero (for the first case where T was originally 1) and the loop and then the program exits.
The solution to this problem is to ignore characters up to and including the newline.
Add a getchar after cin as the \n after the input of T stays in buffer.
std::cin >> T;
getchar();
This is a strange way to do it. So you ask the user to tell the program, before any other input, how many lines will follow? Why not simply:
std::string s;
while (getline(std::cin, s)) {
std::cout << s << std::endl;
}
(This will simply echo every line (press enter to end the line) until end-of-file (Ctrl-d).
Either way, the problem with your code is the while (T--): so why don't you try to see what your T is, and what your getline gives you on each iteration? (I will let you figure it out on your own). Why not use the idiomatic:
for (int i = 0; i < T; ++i)
?
P.S. If you want to read sentences, and not lines, you might want to consider reading up to a delimiter (for example .). getline will do that for you, too:
getline(std::cin, s, '.');

cin.get() in a loop

I was trying to read from standard input. The first line is the number of lines that I will read. The lines that I read next will be printed again. Here is the code:
#include <iostream>
using namespace std;
int main()
{
int n;
cin >> n;
for (unsigned int i = 0; i < n; ++i)
{
char a[10];
cin.get (a, 10);
cout << "String: " << a << endl;
}
return 0;
}
When I run it and give number of lines, the program exits. I haven't figured out what's going on, so I've decided to ask it here.
Thanks in advance.
Mixing formatted and unformatted input is fraught with problems. In your particular case, this line:
std::cin >> n;
consumes the number you typed, but leaves the '\n' in the input stream.
Subsequently, this line:
cin.get (a, 10);
consumes no data (because the input stream is still pointing at '\n'). The next invocation also consumes no data for the same reasons, and so on.
The question then becomes, "How do I consume the '\n'?" There are a couple of ways:
You can read one character and throw it away:
cin.get();
You could read one whole line, regardless of length:
std::getline(std::cin, some_string_variable);
You could ignore the rest of the current line:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
As a bit of related advice, I'd never use std::istream::get(char*, streamsize). I would always prefer: std::getline(std::istream&, std::string&).
Adding a cin.get() before cin.get(a, 10) will solve your problem because it will read the remaining endline in the input stream.
I think it is important to know this when you are using cin : http://www.cplusplus.com/forum/articles/6046/

returning a string from a c++ function

I'm a beginner and I've been going through a book on C++, and I'm on a chapter on functions. I wrote one to reverse a string, return a copy of it to main and output it.
string reverseInput(string input);
int main()
{
string input="Test string";
//cin>>input;
cout<<reverseInput(input);
return 0;
}
string reverseInput(string input)
{
string reverse=input;
int count=input.length();
for(int i=input.length(), j=0; i>=0; i--, j++){
reverse[j]=input[i-1];
}
return reverse;
}
The above seems to work. The problem occurs when I change the following code:
string input="Test string";
to:
string input;
cin>>input;
After this change, the reverse function returns only the reverse of the first inputted word, instead of the entire string. I can't figure out where I am going wrong.
Lastly, is there a more elegant way of doing this by using references, without making a copy of the input, so that the input variable itself is modified?
The problem is with cin. It stops reading after the first space character is read.
See the "cin and strings" section of this tutorial: http://www.cplusplus.com/doc/tutorial/basic_io/
You can use getline(cin, input); to do what you want.
cin>>input; reads a word, not a line.
Use e.g. getline(cin, input); to read a line
cin >> input reads a word. To read an entire line you should use getline
getline(cin, input);
A debugger is very useful in this cases, you can just see the values of the variables stepping through the program.
A simple cout << input; would have helped you too but if you still don't have a good IDE with integrate debugger I would suggest you to use one. Eclipse is good and open source. Visual studio 2010 express is good and free if you are on windows.
Try this: istream& getline ( istream& is, string& str );
It takes an entire line from a stream you give, e.g. cin and saves it into a string variable. Example:
getline(cin, input);
cin.getline(...) would work on C-style character buffers.
Inplace reverse function was already answered in detail here:
How do you reverse a string in place in C or C++?
The problem with your code is that std::cin reads character till it encounters a character for which std::isspace(c) returns true. So spaces and newlines are all such characters which returns true when passing to std::isspace.
So what you need basically is, std::getline:
std::string input;
if ( std::getline(std::cin, input))
{
std::cout << reverseInput(input);
}
else
{
std::cout <<"error while reading from standard input stream";
}
As for your question about references and copying:
string& reverseInput(string& input)
{
for (i = 0, j = input.length()-1; i < j; i++, j--)
{
char c = input[i];
input[i] = input[j];
input[j] = c;
}
return input;
}
You pass your argument as reference, and you return a reference. No copying involved, and in a body, you don't define any new string, you are working on the same instance.
This is not an error in your reverse function, but the standard behaviour of istream::operator>>, which only reads until the first whitespace character.
You need to use cin.getline(), cin >> s will only read the first word (delimited by space)

How to read space separated numbers from console?

I'm trying to do a simple task of reading space separated numbers from console into a vector<int>, but I'm not getting how to do this properly.
This is what I have done till now:
int n = 0;
vector<int> steps;
while(cin>>n)
{
steps.push_back(n);
}
However, this requires the user to press an invalid character (such as a) to break the while loop. I don't want it.
As soon as user enters numbers like 0 2 3 4 5 and presses Enter I want the loop to be broken. I tried using istream_iterator and cin.getline also, but I couldn't get it working.
I don't know how many elements user will enter, hence I'm using vector.
Please suggest the correct way to do this.
Use a getline combined with an istringstream to extract the numbers.
std::string input;
getline(cin, input);
std::istringstream iss(input);
int temp;
while(iss >> temp)
{
yourvector.push_back(temp);
}
To elaborate on jonsca's answer, here is one possibility, assuming that the user faithfully enters valid integers:
string input;
getline(cin, input);
istringstream parser(input);
vector<int> numbers;
numbers.insert(numbers.begin(),
istream_iterator<int>(parser), istream_iterator<int>());
This will correctly read and parse a valid line of integers from cin. Note that this is using the free function getline, which works with std::strings, and not istream::getline, which works with C-style strings.
This code should help you out, it reads a line to a string and then iterates over it getting out all numbers.
#include <iostream>
#include <sstream>
#include <string>
int main() {
std::string line;
std::getline(std::cin, line);
std::istringstream in(line, std::istringstream::in);
int n;
vector<int> v;
while (in >> n) {
v.push_back(n);
}
return 0;
}
Also, might be helpful to know that you can stimulate an EOF - Press 'ctrl-z' (windows only, unix-like systems use ctrl-d) in the command line, after you have finished with your inputs. Should help you when you're testing little programs like this - without having to type in an invalid character.
Prompt user after each number or take number count in advance and loop accordingly.
Not a great idea but i saw this in many applications.