std::cin:: and why a newline remains - c++

Reference Why is the Console Closing after I've included cin.get()?
I was utilizing std::cin.get()
#include<iostream>
char decision = ' ';
bool wrong = true;
while (wrong) {
std::cout << "\n(I)nteractive or (B)atch Session?: ";
if(std::cin) {
decision = std::cin.get();
if(std::cin.eof())
throw CustomException("Error occurred while reading input\n");
} else {
throw CustomException("Error occurred while reading input\n");
}
decision = std::tolower(decision);
if (decision != 'i' && decision != 'b')
std::cout << "\nPlease enter an 'I' or 'B'\n";
else
wrong = false;
}
I read basic_istream::sentry and std::cin::get.
I chose instead to use std::getline as the while loop is executing twice because the stream is not empty.
std::string line; std::getline(std::cin, line);
As the reference I posted above states within one of the answers, std::cin is utilized to read a character and std::cin::get is utilized to remove the newline \n.
char x; std::cin >> x; std::cin.get();
My question is why does std::cin leave a newline \n on the stream?

Because that's its default behavior, but you can change it. Try this:
#include<iostream>
using namespace std;
int main(int argc, char * argv[]) {
char y, z;
cin >> y;
cin >> noskipws >> z;
cout << "y->" << y << "<-" << endl;
cout << "z->" << z << "<-" << endl;
}
Feeding it a file consisting of a single character and a newline ("a\n"), the output is:
y->a<-
z->
<-

It's pretty simple. For example if you would like to write a file with stored names of cities when reading it you wouldn't want to read names with newline characters.
Besides that '\n' is character as good as any other and by using cin you are just fetching one character so why should it skip over anything?
In most use cases when reading char by char you don't want to skip any character because probably you want to parse it somehow, When reading string you don't care about white spaces and so on.

Related

Ending an input stream with a specified character, such as '|'?

Currently learning C++, newbie.
I have an issue when ending the input with the '|' character, my program skips to the end/ends and does not allow for further input. I believe it is because std::cin is in an error state due to inputting a char when expecting an int, so i have tried to use std::cin.clear() and std::cin.ignore() to clear the issue and allow the remainder of the programme to run but I still cannot seem to crack it, any advice appreciated.
int main()
{
std::vector<int> numbers{};
int input{};
char endWith{ '|' };
std::cout << "please enter some integers and press " << endWith << " to stop!\n";
while (std::cin >> input)
{
if (std::cin >> input)
{
numbers.push_back(input);
}
else
{
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max());
}
}
And then pass the vector to a function to iterate through x amount of times and add each element to a total, but the program always skips past the user input:
std::cout << "Enter the amount of integers you want to sum!\n";
int x{};
int total{};
std::cin >> x;
for (int i{ 0 }; i < x; ++i)
{
total += print[i];
}
std::cout << "The total of the first " << x << " numbers is " << total;
Please help!
When the use enters a "|" (or anything that is not an int), the loop ends and the error handling that is inside the loop does not execute. Just move the error code to outside the loop. Also, you read from stdin twice which will skip every other int.
while (std::cin >> input) {
numbers.push_back(input);
}
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Note: If you want to specifically check for "|" can change to something like this:
while (true) {
if (std::cin >> input) {
numbers.push_back(input);
}
else {
// Clear error state
std::cin.clear();
char c;
// Read single char
std::cin >> c;
if (c == '|') break;
// else what to do if it is not an int or "|"??
}
}
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

Why is a space in the string making my code loop infinitely? [duplicate]

This question already has answers here:
Infinite loop with cin when typing string while a number is expected
(4 answers)
Closed 6 years ago.
I have the following code which simply takes a string and find each character's index in the alphabet.
void encrypt()
{
string alpha = "abcdefghijklmnopqrstuvwxyz";
string word;
vector<char> temp;
char a, b;
cout << "Enter string to encrypt: \n";
cin >> word;
for (int i=0; i<word.length(); i++)
{
bool t = false;
a = word[i];
for (int j=0; j<alpha.length(); j++)
{
b = alpha[j];
if (a == b)
{
cout << a << "'s index = " << j+1 << endl;
t = true;
}
}
if (t == false)
{
cout << "space here\n";
}
}
}
when i input a word/string with no space the code works fine but when i input a string with a space the program goes into an infinite loop.
edit main() added due to request:
main()
{
int a;
bool b = false;
while (b == false)
{
cout << "1. Encrypt a string\n";
cout << "2. Decrypt a string\n";
cout << "3. Exit\n";
cout << endl;
cin >> a;
cout << endl;
if (a == 1)
{
encrypt();
}
else if (a == 2)
{
decrypt();
}
else if (a == 3)
{
b = true;
}
}
return 0;
}
cin >> word;
will read only the first word and leave the second word in the input stream. After that, the call
cin >> a;
will result in an error unless the second word starts with a number. Once the program enters a state of error, nothing is read and the program stays in a loop.
To diagnose problems like these, always check the state of the stream after a read operation.
if ( cin >> word )
{
// Use word
}
else
{
// Deal with error.
}
if ( cin >> a )
{
// Use a
}
else
{
// Deal with error.
}
To address your real problem, don't use operator>> to read space separated string. Use getline (and use a variable name different from word).
std::string str;
if ( getline(std::cin, str) )
{
// Use str
}
else
{
// Deal with error.
}
However, in order to use getline successfully, you have to make sure that after a is read, you ignore the rest of the line. Otherwise, the rest of the line will be read by getline.
if ( cin >> a )
{
// Ignore rest of the line
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Use a
}
else
{
// Deal with error.
}
Replace cin >> word; with getline(cin, word);. It will accept a line as input. Which will resolves your input containing spaces.
As far as infinite loop concern, clear the error bits on the stream cin.clear();
You can check whether cin is accepting the space separated string completely, by doing a cout instantly after the cin. If cin is not accepting the space separated string, then try using getline
Issue resolved:
Use the following:
cout << "Enter string to encrypt: ";
scanf(" %[^\n]s",word);
for (int i=0; word[i]!='\0'; i++)
{
use
include <cstdio>
Hope this solves the problem!! I will get back to you with the solution using string..

c++ std::cin being ignored (buffer?) [duplicate]

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)

Testing for a space character inside a string...?

I'm trying to test if a character in a string is a space, and I'm getting extremely frustrated:
string my_string;
cin >> my_string;
for (int i = 0; i < my_string.length(); i++)
{
if (my_string[i] == ' ') // this never becomes true...
{
cout << "this text should pop, but never does" << endl;
}
}
I'm not getting any errors and I've looked online, but people on different forums say this is how to test for a space. Uh.
when you say
cin >> my_string;
you are taking formatted input. std::cin discards any whitespace in that line, and it reads up to and yields only a single word.
try instead
std::string my_string;
std::getline(std::cin, my_string);
to get a single line, or
#include <iterator>
// ...
std::string my_string((std::istreambuf_iterator<char>(std::cin)),
std::istreambuf_iterator<char>());
to get everything up to an end-of-file mark into the string.
Thats because cin stops reading at the first whitespace so you never actually read the entire sentence but the first word. Use getline instead.
std::string my_string;
std::getline(std::cin, my_string);
for (int i = 0; i < my_string.length(); i++)
{
if (my_string[i] == ' ') // this never becomes true...
{
std::cout << "this text should pop, but never does" << std::endl;
}
}
Additionnally to test whether a space is present use std::string::find!
std::string my_string;
std::cin >> my_string; // please do not use « using namespace std; » if possible
size_t space_position = my_string.find(' ');
if(space_position != std::string::npos)
{
std::cout << "found space" << std::endl;
}

C++ STD Cin error in while loop

Why when I entered the loop below and I type something the first instruction
cmdstd:getline(std::cin,cmdInput); does not read the input entered. For instance if I entered "b 8" it should display "cmd is b 8", but it skips to the next read std::getline(std::cin, input); and displays "it is b" instead
while (editingMode == TRUE) {
std::getline(std::cin, cmdInput);
istringstream cmdiss(cmdInput);
cout << "you entered: " << cmdInput <<endl;
if (cmdInput != "") {
copy(istream_iterator<string>(cmdiss),
istream_iterator<string>(),
back_inserter<vector<string> >(tokens));
std::cout << "cmd is " <<tokens.at(0) << std::endl;
}
//*************************
std::getline(std::cin, input);
istringstream iss(input);
if(input != ""){
copy(istream_iterator<string>(iss),
istream_iterator<string>(),
back_inserter<vector<string> >(tokens));
std::cout << "it is " << tokens.at(0) <<std::endl;
createInstruction(tokens);
}
Perhaps you have a newline character left in the input buffer, from an earlier input? This is a common error.
Lets say that your program first reads an integer with cin >> x, and then a line with getline(cin, cmdline). The user types an integer, followed by the ENTER key. The cin >> x will read the integer, but the ENTER key, interpreted as a newline character, will be left in the input buffer.
When your program then goes on to read a complete line with getline(cin, cmdline), it will read the very short line that consists of just that left-over newline character. This looks like the program "skips to the next read".
There's nothing wrong with the code. It just doesn't do what you think it should :) If you want to print the whole line entered rather than the first word, don't print tokens[0]; print the input line.
Both sections do the same thing:
read a line into a string
create an istream from that line
read the words from that istream into an array of strings called 'tokens'
print the first word
tokens.at(0) is the first word, obviously. check tokens.size() or iterate over tokens if you want to look for arguments like "8".
are you sure editingMode is TRUE?
The problem is mixing >> extractions with getline, leaving a newline (or other input) in the buffer. Blindly using ignore will hide logic errors, such as input of "42 abc" followed by cin >> some_int; cin.ignore(...);. What you really have to do is "extract" the blank line:
int main() {
using namespace std;
int n;
string s;
cout << "Enter a number: "
cin >> n >> blankline; // <---
if (cin) {
cout << "Enter a line of text: ";
getline(cin, s);
}
if (!cin) {
clog << "Sorry, I can't do that.\n";
return 1;
else {
cout << "Input successful, now processing values: " << n << s << '\n';
}
return 0;
}
Thankfully, this is easy:
template<class C, class T>
std::basic_istream<C,T>&
blankline(std::basic_istream<C,T>& s,
typename std::basic_istream<C,T>::char_type delim) {
if (s) {
typename std::basic_istream<C,T>::char_type input;
if (!s.get(input) && s.eof()) {
s.clear(s.eofbit);
}
else if (input != delim) {
s.putback(input);
s.setstate(s.failbit);
}
}
return s;
}
template<class C, class T>
std::basic_istream<C,T>& blankline(std::basic_istream<C,T>& s) {
blankline(s, s.widen('\n'));
return s;
}