954,492 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

cin in do while loop

Been developing for years under web based services like PHP and SQL, and I thought it would be a good idea that I come back and learn C++. Been enjoying it, but I got this one thing that is just driving me nuts.

In the do while loop after the cin is set on the first loop it goes into a death spin. In the 2nd example posted below it works just fine. Its as if the cin does not take a 2nd input after the first loop and just assumes its the same as the first input.

#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

class customerClass {
	string masterArray[2][255];

	public:
	void getActions(int);
	void saveInArray(int, string);
	string readArray(int,int);
};
string customerClass::readArray(int x, int y) {
	cout << masterArray[x][y];
}
void customerClass::saveInArray(int a, string sx) {
	switch(a) {
		case 1:
		masterArray[a][0] = sx;
		break;
	}
}
void customerClass::getActions(int actions) {
	string uInput;
	switch(actions) {
		case 1:
			cout << "Options: (2) Add Name, (3) Add Address, (0) Exit: ";
		break;
		case 2:
			cout << "Customer Name ";
			getline(cin, uInput);
			saveInArray(1,uInput);
		break;
		case 3:
			cout << "Customer Address: ";
			getline(cin,uInput);
		break;
		default:
			// exit(1);
		break;
	}
}
int main() {
	customerClass rect;
	int n;
	rect.getActions(1);
	do {	
		cin >> n;
		rect.getActions(n);
	}while(n!=0);
return 0;
}


2nd code test that works fine:

// number echoer

#include <iostream>
using namespace std;

int main ()
{
  unsigned long n;
  do {
    cout << "Enter number (0 to end): ";
    cin >> n;
    cout << "You entered: " << n << "\n";
  } while (n != 0);
  return 0;
}
l3vi
Newbie Poster
4 posts since May 2009
Reputation Points: 14
Solved Threads: 0
 

This may help--

#include <iostream>
#include <string>
#include <cstdlib>
#include <sstream>

using namespace std;

class customerClass {
	string masterArray[2][255];

	public:
	void getActions(int);
	void saveInArray(int, string);
	string readArray(int,int);
};
string customerClass::readArray(int x, int y) {
	cout << masterArray[x][y];
}
void customerClass::saveInArray(int a, string sx) {
	switch(a) {
		case 1:
		masterArray[a][0] = sx;
		break;
	}
}
void customerClass::getActions(int actions) {
    stringstream ss (stringstream::in | stringstream::out);
	string uInput;
	switch(actions) {
		case 1:
			cout << "Options: (2) Add Name, (3) Add Address, (0) Exit: ";
		break;
		case 2:
			cout << "Customer Name ";
			cin >> uInput;
            ss << uInput;
            saveInArray(1,ss.str());
		break;
		case 3:
			cout << "Customer Address: ";
			cin >> uInput;
			ss << uInput;
		break;
		default:
			// exit(1);
		break;
	}
}
int main() {
	customerClass rect;
	int n;
	
	do {
        rect.getActions(1);
		cin >> n;
		
		if(cin.fail()){
             cout << "bad input!" << endl;
             cin.clear();
             cin.ignore(INT_MAX, '\n');
             continue;
        }
		
		rect.getActions(n);
	}while(n!=0);
return 0;
}


You're probably wondering why I bothered with the sstream?

Consider the potential problem with bad input for the input buffer, cin.

You can pass information from cin to another buffer. That way if
you encounter extraction problems, its no longer cin's responsibility
to handle it - its that of the buffer that you are performing extraction on!

I personally, never like messing with cin directly. Using temporary buffers
can simplify problems with the standard input buffer at the cost of space
in your program.

Alex Edwards
Posting Shark
972 posts since Jun 2008
Reputation Points: 392
Solved Threads: 109
 

>This may help
Yeah, Alex, it will surely help him, but you don't explain him what you've changed to make his code work ...

To the OP:
It's because of the getline function, so you'll have to flush the input stream each time to make your code work as expected, there's a thread about flushing the input stream, you can find it here :)

tux4life
Nearly a Posting Maven
2,350 posts since Feb 2009
Reputation Points: 2,134
Solved Threads: 243
 

>This may help Yeah, Alex, it will surely help him, but you don't explain him what you've changed to make his code work ...

To the OP: It's because of the getline function, so you'll have to flush the input stream each time to make your code work as expected, there's a thread about flushing the input stream, you can find it here :)

Yeah, after realizing how tired I was I also realized that I never answered the original question.

the getline function is accepting characters for your string but it doesn't seem like you're specifying a delimeter for the getline (by default it should be the newline char) nor are you flushing the input buffer after you push characters in it, so whan cin>>n is processed, characters are still in the buffer and then cin gets placed in a fail state.

Actually, Narue's post about this is far more intuitive than I could possibly explain. It wouldn't hurt to take the time to read it.

In this portion of code, after getting input from the user (such as the number for the option) I immediately ignore any characters that were put in the buffer then make a request to get characters in the input buffer until the newline delimiter is met then the characters are stored in the string.

#include <iostream>
#include <string>
#include <cstdlib>

using namespace std;

class customerClass {
	string masterArray[2][255];

	public:
	void getActions(int);
	void saveInArray(int, string);
	string readArray(int,int);
};
string customerClass::readArray(int x, int y) {
	cout << masterArray[x][y];
}
void customerClass::saveInArray(int a, string sx) {
	switch(a) {
		case 1:
		masterArray[a][0] = sx;
		break;
	}
}
void customerClass::getActions(int actions) {
    
	string uInput;
	switch(actions) {
		case 1:
			cout << "Options: (2) Add Name, (3) Add Address, (0) Exit: ";
		break;
		case 2:
			cout << "Customer Name ";
			cin.ignore(INT_MAX, '\n');
			getline(cin, uInput, '\n');
            saveInArray(1,uInput);
		break;
		case 3:
			cout << "Customer Address: ";
			cin.ignore(INT_MAX, '\n');
			getline(cin, uInput, '\n');
		break;
		default:
			// exit(1);
		break;
	}
}
int main() {
	customerClass rect;
	int n;
	
	do {
        rect.getActions(1);
		cin >> n;
		
		if(cin.fail()){
             cout << "bad input!" << endl;
             cin.clear();
             cin.ignore(INT_MAX, '\n');
             continue;
        }
		
		rect.getActions(n);
	}while(n!=0);
return 0;
}
Alex Edwards
Posting Shark
972 posts since Jun 2008
Reputation Points: 392
Solved Threads: 109
 

just for your information you do not need to implicitly define the delimiter as a newline in getline() it is already set there and if you want to change it the you must specify what you want. at least that is according to the msdn for visual c++ 6.0 professional

NathanOliver
Veteran Poster
1,084 posts since Apr 2009
Reputation Points: 215
Solved Threads: 189
 
just for your information you do not need to implicitly define the delimiter as a newline in getline() it is already set there and if you want to change it the you must specify what you want. at least that is according to the msdn for visual c++ 6.0 professional

Yup, that's true: http://www.cplusplus.com/reference/iostream/istream/getline/
:)

tux4life
Nearly a Posting Maven
2,350 posts since Feb 2009
Reputation Points: 2,134
Solved Threads: 243
 

Thanks for the info and link. Alex; if I'm fallowing you right, using stringstream and passing uInput into ss it's moving the data out of the cin buffer into a buffer in ss stringstream?

l3vi
Newbie Poster
4 posts since May 2009
Reputation Points: 14
Solved Threads: 0
 

This article has been dead for over three months

Post: Markdown Syntax: Formatting Help
You