I need to allow the user to enter a writing sample in the console or as a file and have my program split that input into a word vector (one word per item of vector). This is my current code:
while(cin >> inputString) {
wordVector.push_back(inputString);
}
The trouble is, when I run this, it works fine until it reaches the end of the user's input. Then it seems to just endlessly loop.
inputString is type string.
wordVector is type string.
This is the full code: (the broken code is at the bottom)
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
// Debug message flag
const bool DEBUG = false;
// Prototypes
void splitToVectors(vector<string>&,vector<string>&,vector<int>&,int &);
double avSentLength(const vector<string>);
double avWordSyl(const vector<string>,const vector<char>);
double percentSentLong(const vector<int>,int);
int numSyllables(const vector<char>);
void nextScreen(int);
int main() {
// Initialize variables and vectors
bool validate;
int characters,words,sentences = 0,syllables;
string file;
string inputString;
char inputChar;
int input;
vector<string> wordVector;
vector<char> charVector;
vector<string> sentenceVector;
vector<int> numWordsInSent;
// Get writing sample
do {
// Request preferred location
validate = true;
cout << "Would you like to:" << endl;
cout << " 1. Enter the writing sample in the console" << endl;
cout << " 2. Read from a file" << endl << " > ";
// Validate
if(!(cin >> input)) { // This error checking condition functions as the cin
validate = false;
cin.clear();
cin.ignore(100, '\n');
}
if((input < 1) || (input > 2)) {
validate = false;
}
} while(!validate);
// Transfer selected source to wordVector
if(input == 1) {
// Request sample
cout << "Please enter the writing sample below:" << endl << endl;
// Input sample
while(cin >> inputString) {
wordVector.push_back(inputString);
}
}
}
I have not yet learned about iterators. So I came up with the following solution:
I use a getline to take all input and place into a string variable. I then have a for loop run through it, building a temporary string as it goes, until it encounters a space. When it sees a space, it adds the temporary variable to the vector, and resets the temporary variable. It continues this way until it reaches the end of the string.
Are you sure you are hitting Ctrl-D to send the EOF properly? The following code seems to work:
int main()
{
vector<string> words;
std::string inputString;
while (cin >> inputString)
{
words.push_back(inputString);
}
vector<string>::iterator it;
for (it = words.begin(); it != words.end(); it++)
{
cout << *it << "\n";
}
return 0;
}
In an interactive console/compiler while(cin >> inputString) will continue wait for user-input.
It may work on a non-interactive console/compiler that reads data from a static standard input. But it's worth noting that in (most conforming) interactive compilers, cin >> inputString will continue to wait for user input, and will (should) not evaluate to false until there occurs an error in reading input.
You may want to signal the program that input is finished. One way of doing this is to provide a keyword such as EOF which will break the while-loop (although the disadvantage of this is that you can't use EOF in the content of your input).
Related
Here is the code
double enter_number()
{
double number;
while(1)
{
cin>>number;
if(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Invalid input " << endl;
}
else
break;
cout<<"Try again"<<endl;
}
return number;
}
My problem is that when I enter something like 1x, then 1 is taken as input without noticing the character that is left out for another run.
Is there any way how to make it work with any real number e.g. 1.8?
When cin encounters an input it can't properly read in to the variable specified (such as inputing a character into an integer variable), it goes into an error state and leaves the input in it's buffer.
You have to do several things to properly handle this scenario.
You have to test for this error state.
You have to clear the error state.
You have to either alternatively handle the input data that generated the error state, or flush it out and reprompt the user.
The following code provides one of numerous methods of doing these three things.
#include<iostream>
#include<limits>
using namespace std;
int main()
{
cout << "Enter an int: ";
int x = 0;
while(!(cin >> x)){
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Invalid input. Try again: ";
}
cout << "You enterd: " << x << endl;
}
You could just pass in some large value to cin.ignore like 1000 and it's likely to behave exactly the same for all practical purposes.
You can also test cin after the input attempt and handle it that way, something like
if(!cin){//clean up the error} .
Check out the istream reference for other member functions to handle stream state: http://cplusplus.com/reference/iostream/istream/
I would use std::getline and std::string to read the whole line and then only break out of the loop when you can convert the entire line to a double.
#include <string>
#include <sstream>
int main()
{
std::string line;
double d;
while (std::getline(std::cin, line))
{
std::stringstream ss(line);
if (ss >> d)
{
if (ss.eof())
{ // Success
break;
}
}
std::cout << "Error!" << std::endl;
}
std::cout << "Finally: " << d << std::endl;
}
Here is the code
double enter_number()
{
double number;
while(1)
{
cin>>number;
if(cin.fail())
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Invalid input " << endl;
}
else
break;
cout<<"Try again"<<endl;
}
return number;
}
My problem is that when I enter something like 1x, then 1 is taken as input without noticing the character that is left out for another run.
Is there any way how to make it work with any real number e.g. 1.8?
When cin encounters an input it can't properly read in to the variable specified (such as inputing a character into an integer variable), it goes into an error state and leaves the input in it's buffer.
You have to do several things to properly handle this scenario.
You have to test for this error state.
You have to clear the error state.
You have to either alternatively handle the input data that generated the error state, or flush it out and reprompt the user.
The following code provides one of numerous methods of doing these three things.
#include<iostream>
#include<limits>
using namespace std;
int main()
{
cout << "Enter an int: ";
int x = 0;
while(!(cin >> x)){
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Invalid input. Try again: ";
}
cout << "You enterd: " << x << endl;
}
You could just pass in some large value to cin.ignore like 1000 and it's likely to behave exactly the same for all practical purposes.
You can also test cin after the input attempt and handle it that way, something like
if(!cin){//clean up the error} .
Check out the istream reference for other member functions to handle stream state: http://cplusplus.com/reference/iostream/istream/
I would use std::getline and std::string to read the whole line and then only break out of the loop when you can convert the entire line to a double.
#include <string>
#include <sstream>
int main()
{
std::string line;
double d;
while (std::getline(std::cin, line))
{
std::stringstream ss(line);
if (ss >> d)
{
if (ss.eof())
{ // Success
break;
}
}
std::cout << "Error!" << std::endl;
}
std::cout << "Finally: " << d << std::endl;
}
My program takes user data as a tuple and stores it into a vector. There is no limit to how many tuples can be added and vector size changes with the adding of tuples. The program asks the user if they want to add another tuple. If no, the loop exits.
My problem is, when the program was supposed to wait for 'yes' or 'no' input, it skipped the cin and exited the loop.
I have tried searching for solutions, tried clearing the buffer but I am back to square one.
#include <iostream>
#include <string>
#include <tuple>
#include <vector>
using namespace std;
void print(vector<tuple<int, string, string, bool>> const & data)
{
if (data.size() != 0)
{
for (auto row : data)
{
cout << get<0>(row) << ", " << get<1>(row) << ", " << get<2>(row)
<< ", " << get<3>(row) << endl;
}
}
else
{
cout << "\nNO ENTRIES CURRENTLY!";
}
}
int main()
{
int id;
char go;
string name, filePath;
bool flag = false;
typedef tuple<int, string, string, bool> pData;
vector<pData> pList;
do
{
cout << "Enter a Pattern Call:" << endl;
cin >> id >> name >> filePath >> flag;
pList.push_back(make_tuple(id, name, filePath, flag));
cout << "Do You wish to add another: ";
cin.ignore();
cin >> go; //The control skips here and exits the loop.
} while (go == 'y' || go == 'Y');
print(pList);
return 0;
}
I have a hack which seems to work on my Linux Machine.
Add cin.clear() before cin.ignore()
Replace cin.ignore() with cin.ignore(1)
Part of your code should look as below:
cout << "Do You wish to add another: ";
cin.clear();
cin.ignore(1);
cin >> go; //The control skips here and exits the loop.
Look here:
How do I flush the cin buffer?
Using cin is not that easy or safe if user input is not exactly what we want.
I'm having a problem with what should be incredibly simple code. I want to take in an integer between 1 and 3 with error checking. It works fine for checking for numbers that are too large or too small, but when a alpha/number combination is entered, it gets stuck in an infinite loop. Suggestions?
#include <iostream>
using namespace std;
int main(int argc, char *argv[]){
int input;
cout << "\nPlease enter a number from 1 to 3:" << endl;
cout << "-> ";
cin >> input;
while(input< 1 || input> 3){
cout << "\n---------------------------------------" << endl;
cout << "\n[!] The number you entered was invalid." << endl;
cout << "\nPlease re-enter a number from 1 to 3" << endl;
cout << "-> ";
cin >> input;
}
cout << "You chose " << input << endl;
}
The problem is that:
cin >> input;
Will cause the bad bit to be set when you try and read a non numeric value. After that happens any attempt to use the operator>> is silently ignored.
So the way to correct for this is to test if the stream is in a good state and if not then reset the state flags and try and read again. But note that the bad input (that caused the problem) is still on the input so you need to make sure you throw it away as well.
if (cin >> input)
{
// It worked (input is now in a good state)
}
else
{
// input is in a bad state.
// So first clear the state.
cin.clear();
// Now you must get rid of the bad input.
// Personally I would just ignore the rest of the line
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// now that you have reset the stream you can go back and try and read again.
}
To prevent it getting stuck (which is caused by the bad bit being set) read into a string then use a string stream to parse user input. I also prefer this method (for user interactive input) as it allows for easier combination of different styles of reading (ie combining operator>> and std::getline() as you can use these on the stringstream).
#include <iostream>
#include <sstream>
#include <string>
// using namespace std;
// Try to stop using this.
// For anything other than a toy program it becomes a problem.
int main(int argc, char *argv[])
{
int input;
std::string line;
while(std::getline(std::cin, line)) // read a line at a time for parsing.
{
std::stringstream linestream(line);
if (!(linestream >> input))
{
// input was not a number
// Error message and try again
continue;
}
if ((input < 1) || (input > 3))
{
// Error out of range
// Message and try again
continue;
}
char errorTest;
if (linestream >> errorTest)
{
// There was extra stuff on the same line.
// ie sobody typed 2x<enter>
// Error Message;
continue;
}
// it worked perfectly.
// The value is now in input.
// So break out of the loop.
break;
}
}
#include <iostream>
#include <string>
using namespace std;
int validatedInput(int min = 1, int max = 3)
{
while(true)
{
cout << "Enter a number: ";
string s;
getline(cin,s);
char *endp = 0;
int ret = strtol(s.c_str(),&endp,10);
if(endp!=s.c_str() && !*endp && ret >= min && ret <= max)
return ret;
cout << "Invalid input. Allowed range: " << min << "-" << max <<endl;
}
}
int main(int argc, char *argv[])
{
int val = validatedInput();
cout << "You entered " << val <<endl;
return 0;
}
Most of these answers include unnecessary complexity.
Input validation is a perfect time to use a do-while
do{
cout << "\nPlease enter a number from 1 to 3:" << endl;
cout << "-> ";
if(!cin){
cout << "Invalid input"
cin.clear()
cin.ignore(numeric_limits<streamsize>::max(), '\n');
}
}while(!(cin >> input))
Use numeric_limits<streamsize>::max() to completely clear the
buffer after a failed cin.
Use cin.clear() to reset the fail flag on cin so !cin wont
always evaluate false.
cin.fail() is fine. However some would consider !cin more natural.
from my previous post https://stackoverflow.com/a/43421325/5890809
You declared input as int but when you write an alphanumeric character to input it will try to implicitly convert it into integer. But you error checking does not account for this.
Ur problem can be easily solved by changing your while loop. instead of checking this how about you check
while(input!=1 || input!=2 || input!=3)
double checkInput() {
double add;
cout << "\n" << endl;
cin >> add;
if (cin.fail()==true)
{
cin.clear();
cin.ignore(INT_MAX, '\n');
cout << "Incorrect input"<<endl;
}
else
{
return add;
}
}
I use this bit of code to filter out character inputs eg "Blarg","bat12cat" and similar inputs where the character/letter come first but when i test with "1gold" ,"0.05cake" etc where number comes first then letters,the program accepts the all numbers up to the first instance of a letter.
My understanding is that it is the cin.ignore() that is causing the issue and is allowing the numbers through.
What would let inputs like"0.05Cats" be ignored/skipped altogether?.
Searching online,people suggest using getline() and stringstream.
Thank you.
When you input something like 1.5dog and then use cin >> some_double; >> is going to extract out a double until it can't read any more. So some_double gets the 1.5 and dog is still in the stream. This is not a failure and as such the failbit is not set. Since it is not set you skip your if statement and return the double value while the rest of the input stays in the stream and will cause you issues the next time you try to read from the stream. My suggestion is to change how you read your inputs. You can take in the input via a std::string and then convert it to the desired type. Then if the conversion fails you you can signal that you had a failure. I would use something like:
bool read_double(std::istream & is, double & number)
{
std::string line;
getline(is, line);
std::size_t pos = 0;
double temp = stod(line, &pos);
if (pos != line.size()) // there is extra content in the streams
return false;
number = temp;
return true;
}
And you can see it working with this Live Example
Usually there is more than one way to do the right thing. Using "c++(11) regex class object" would help you. You can edit regex for your needs (for example to include hex numbers by adding -a,b,c,d,e,f).
#include <iostream>
using namespace std;
#include <string>
using std::string;
#include <regex>
void main()
{
string input;
std::regex reg("[-+]?([0-9]*\.[0-9]+|[0-9]+)");
cout << "Please enter a double type\n";
while (cin >> input)
{
if (std::regex_match(input, reg))
{
std::cout << "Valid input\n";
break;
}
else
{
cout << "Invalid input\n";
cout << "Please enter a double type\n";
}
}
double do_with = std::stod(input,NULL);
cout << "the double is : " << do_with << endl;
cin >> input; // to hold the shell
}