cin.get() isn't working as it should [duplicate] - c++

This question already has an answer here:
Cin.get() issue with C++ [duplicate]
(1 answer)
Closed 9 years ago.
First, here is the code:
using namespace std;
cout << "\aOperation \"HyperHype\" is now activated!\n";
cout << "Enter your agent code:_______\b\b\b\b\b\b\b";
long code;
cin >> code;
cin.get();
cout << "\aYou entered " << code << ".....\n";
cout << "\aCode verified! Proceed with Plan Z3!\n";
cin.get();
return 0;
It compiles without a problem and runs almost without flaw; after 'code' receives its value from standard input, the final string flashes up for maybe a millisecond and the program dies. As you can see I placed the 'cin.get()' member function after the final string in order to prevent this, yet it continues to die after the 'cin >> code;' line.
This method has worked for all of my other practice programs up until now, and there is nothing structurally different between this program and any of the others.
Any suggestions?
(Assume proper header files and preprocessor directives are in place.)

You are reading the newline character you already entered earlier with your final get() call. You might want to ignore all characters up to and including the first newline before waiting for some other input:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cin.get();
You can shorten this to become
std::cin >> std::ws;
if it is OK requiring to enter a non-whitespace character to terminate the program: the std::ws manipulator extracts whitespace characters until either a non-whitespace character or the end of the stream is reached.
Note that std::istream::get() actually does work as it should! It just reads the next character. It just happens not to do what you did expect.

Add a cin >> code line instead of the two cin.get(). If the program just closes anyway, then this would probably be the simplest thing to do.

Related

Visual C++ using Console: Char/String compatibility issues with while loop

cout << "Would you like to make another transaction? (y/n)" << endl;
cin >> repeat_transaction;
static_cast<char>(repeat_transaction);
while (repeat_transaction != 'y' && repeat_transaction != 'n')
{
cout << "Invalid selection: Please enter y or n";
cin >> repeat_transaction;
static_cast<char>(repeat_transaction);
}
During the Invalid selection loop, I once accidentally pressed "mn". I noticed the console read out Invalid selection..., So, it did in fact finish and re-enter the while loop. However, after this the console terminated the program. If you enter a single character 'a' or 'y' or 'n' it acts just as it should. Ending or not ending. This was before I attempted to use static_cast to force the truncation of the user input.
Since you managed to get this program to compile I can only assume that repeat_transaction was specified as a char and not a std::string.
When you use cin to get a character it only gets one character but it doesn't flush the buffer. I believe you understand this issue since you wrote This was before I attempted to use static_cast to force the truncation of the user input. . You can attempt to use cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); instead of static_cast<char>(repeat_transaction); after each call to cin >> repeat_transaction; . There are downsides to this. If you enter 'mn' it will work as expected. It reads the m which is not y or n and then flushes the extra characters until it finds end of line \n. If you do nm, n will match and the m will be thrown away. So in that case it will accept nm as valid and exit the loop.
There are other ways that may be easier and give you the effect closer to what you are looking for. Instead of reading a character at a time you can read an entire line into a string using getline (See the C++ documentation for more information). You can then check if the length of the string is not equal to 1 character. If it's not length 1 then it is invalid input. If it is 1 then you want to check for y and n. Although basic (and not overly complex) this code would do a reasonable job:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string repeat_transaction;
cout << "Would you like to make another transaction? (y/n)" << endl;
getline(cin, repeat_transaction);
while (repeat_transaction.length() != 1 || (repeat_transaction != "y" && repeat_transaction != "n"))
{
cout << "Invalid selection: Please enter y or n";
getline(cin, repeat_transaction);
}
return 0;
}
I said reasonable job since one deficiency you might see is that you want to trim white spaces from the beginning and end. If someone enters n or y with a space or tab in front it will be seen as invalid (whitespace at the end would be similar). This may not be an issue for you, but I thought I would mention it.
On a final note, you may have noticed I used using namespace std;. I did so to match what was in the original question. However, this is normally considered bad practice and should be avoided. These StackOverflow answers try to explain the issues. It is better to not do it and prepend all standard library references with std::. For example string would be std::string, cin would be std::cin etc.

C++ Press Enter to Terminate Program [duplicate]

This question already has answers here:
Cin.Ignore() is not working
(4 answers)
Closed 9 years ago.
I am writing a C++ program and I need to program to end/terminate after the user hits enter.
This is what I have:
cout << "Press Enter to End" << endl;
cin.ignore(); //ends after the user hits enter
return 0;
But it doesn't work. Any advice?
I sense that you had some formatted input earlier in your program, i.e., it looks something like this:
std::cin >> value;
do_something(value);
std::cout << "press enter to end\n";
std::cin.ignore();
If that is the case, you have some character in the input buffer from the time you entered value. For example, there can be a '\n' but it can be any odd other characters, too. This character will be read when the program encounters std::cin.ignore().
What you probably want to is to get rid of the characters currently known to be in the buffer. This isn't quite what would be done as this can still miss characters which are already entered but not, yet, transferred but there is no portable approach to clear all potential characters (it is normally not a problem because hardly any user interface depends on character input from a terminal).
To ignore the characters which are known to be present you need to start off by breaking the connection between <stdio.h> and IOStreams using std::ios_base::sync_with_stdio() and later consume the known characters entered after your last read, e.g.,
#include <iostream>
int main()
{
std::ios_base::sync_with_stdio(false);
int x;
std::cin >> x;
std::cin.ignore(std::cin.rdbuf()->in_avail());
std::cout << "press enter\n";
std::cin.ignore();
}
The odd call to sync_with_stdio() is necessary to have the IOStreams actually buffer the characters received from the system rather than reading characters individually. As a nice side effect it dramatically improves the performance of using std:cin, std::cout, and the other standard stream objects.
maybe add system("pause") in the end of code; (include first). I guess you want enter to close termination.

Getline problem [duplicate]

This question already has an answer here:
What am I not understanding about getline+strings?
(1 answer)
Closed 7 years ago.
I've got following code:
system("CLS");
string title;
string content;
cout << "Get title." << endl;
getline(cin,title);
cout << "Get content." << endl;
getline(cin,content);
The problem is - application is not asking about tittle, I've got Get title, get content and then waiting for user input, it's not waiting for user input after get title.bDo I have to add any break or smth?
Or maybe, that isn't the best idea to read whole text line from user input?
If you have a cin >> something; call prior to your system() call.
For example, taking input into an integer. When cin >> myintvar; (or similar) then the integer is placed in myintvar and the '\n' gets sent along in the stream. The getline picks the \n up as indicative of the end of a line of input, so it is effectively "skipped".
Either change the cin >> to a getline()
or call cin.ignore() to grab the '\n'(or better, call a cin.ignore (std::numeric_limits<std::streamsize>::max(), '\n' ); to flush the input buffer-- but be sure you're not throwing away valuable input in the process).
I'd bet that you have something like a menu for selecting options ( as a numeric type ) and after that you try to read the lines.
This happens because after std::cin read some value the remaining '\n' was not processed yet, the solution would be to include #include <limits> and then put std::cin.ignore(std::numeric_limits<streamsize>::max(),'\n');
before your getline(cin,title);
It is because when you use getline() it ignores the newline at the end of the line and feeds it into the input queue, so when your getline function is called for next time it encounters the newline character discarded by the previous getline() and so it considers that as end of your input string. So thats why it doesn't take any input from you. You could use something like this
getline(cin,title);
cin.get();
hope this works.

C instruction is being reordered when cin cout and gets is used consecutively

Does anyone knows why C instruction is being reordered when cin cout and gets is used consecutively here?
I am using Dev-C++ 4.9.9.2.
#include<iostream>
using namespace std;
int main(){
char a[10],b;
for(;;){
cout<<"\ncin>>b:";
cin>>b;
cout<<"gets(a):";
gets(a);
cout<<"cout<<a<<b:"<<a<<" "<<b<<"\n\n";
}
}
I got an output like:
cin>>b:132
gets(a):cout<<a<<b:32 1
cin>>b:465
gets(a):cout<<a<<b:65 4
cin>>b:312242
gets(a):cout<<a<<b:12242 3
cin>>b:1
gets(a):cout<<a<<b: 1
cin>>b:
It seemed like some input for cin was passed in gets.. and it also appears that instructions were reordered like:
cin>>b;
gets(a);
cout<<"gets(a):";
instead of,
cin>>b;
cout<<"gets(a):";
gets(a);
cin>>b read just a character, leaving the rest of the input to be read by later input operation. So gets sill has something to read and don't block.
At the first cin >> b, there is no input available. You enter '132\n' (input from terminal is usually made line by line) in a buffer and just get the 1 out of it. gets reads the next characters 32 and the \n which terminates gets. It doesn't need to read something more from the terminal.
Nothing has been re-ordered.
your input from keyboard has been send only when you pressed enter. At that time, there have been enough data to execute the cin<<b, the following cout, then to complete the gets(a).
In others words, the execution of cin<<b is suspended to the reception of a char. But that char is not send to the program until you pressed 'Enter' (this is because of your terminal settings). When you press 'Enter', the first char is received by cin<<b and the remaining is buffered. cout executes, and when it is the turn of gets(a), the buffer delivers the remaining chars included the carriage return, so gets(a) completes as well, with the data you entered to complete the cin<<b instruction.
Try to simply press enter for the cin<<b to complete, then you'll see the cout, and then you will have the gets(a) waiting for your inputs.
While not really answering your question...
The idiomatic way in C++ would rather be to use getline. It's an accident of history that does not make it part of the iostream interface directly, but it really is the function to use for inputs.
Shameless plug from the website:
// getline with strings
#include <iostream>
#include <string>
int main () {
std::string str;
std::cout << "Please enter full name: ";
getline (std::cin,str);
std::cout << "Thank you, " << str << ".\n";
}
The main advantage of getline, in this version, is that it reads up until it encounters a line-ending character.
You can specify your own set of "line-ending" characters in the overload accepting a third parameter, to make it stop on commas or colons, for example.
The code isn't reordered, but std::cout is buffered so the string doesn't appear immediately on your display. Therefore gets(a) will be executed with the output still in the buffer.
You can add a <<flush after the output string to make cout flush it's buffer.
When you use std::cin, it knows how to tell std::cout to flush the buffer before the input starts, so you don't have to.

C++ Getline simple error [duplicate]

This question already has an answer here:
What am I not understanding about getline+strings?
(1 answer)
Closed 7 years ago.
I would like to point I am not good in C++, I usually use C but i thought that get to know some C++ basic will be good so I need to send data to server and normal std::cin >> variable can't do it because it only reads input to space so I read about getline and it's working great, but when I do something liek this in infinite loop:
for (;;)
{
std::cout << "Hello" << std::endl;;
std::getline(std::cin,darek.wiadomosc);
}
Durning first itteration it shows on screen double Hello like:
Hello
Hello
String that is being entered
But after one loop it shows everything good. It's problem with getline I'm sure because when I changed it to std::cin >> just for test it worked. Can anybody answer to my simple question?
std::cin leaves the terminator in the stream (be it a space or a newline).
So if you do:
std::string foo, bar;
std::cin >> foo;
std::getline(std::cin, bar);
with input as:
Hello
World
bar will end up with the empty string, not "World", because getline will stop at the first newline, which is the one after "Hello".
To bring this back to your question, if you have instances of std::cin >> before the start of your loop, you may have a stray newline, making the first iteration behave in unexpected ways. You can use std::cin.ignore to ignore any newlines left in the stream.