Why do I get ESC successfully only by _getch()? - c++

I want to do somethings when I press ESC. First I found this: How to read until ESC button is pressed from cin in C++
Then I tried to use cin.get() like answers in that question.
using namespace std;
const int ESC = 27;
char c;
c = cin.get();
if (c == ESC) {
...;
} else {
...;
}
But it never works! cin.get() can get 'a', '1', etc. It just doesn't work When I enter Esc. I've also tried cin >> c and couldn't catch Esc either.
Then I use int _getch( void ); in <conio.h> instead of cin.get(). It works!
_getch() seems to be C-style function, therefore I don't like to use it in C++ codes. And I don't understand why cin.get() doesn't work in my code but it seems to work in others' according to answers in the previous link.
It's on Windows.
Besedes, it's my first time to ask a question in stackoverflow and I haven't mastered English well. Sincerely hope for your answers and comments if I mistook something.

Because std::cin.get() reads characters from the console window, however it is not possible to actually 'write' the escape character; therefor it never catches it.
from cplusplus.com
Internally, the function accesses the input sequence by first constructing a sentry object (with noskipws set to true). Then (if good), it extracts characters from its associated stream buffer object as if calling its member functions sbumpc or sgetc, and finally destroys the sentry object before returning.
To catch the escape key on Windows:
if(GetAsyncKeyState(VK_ESCAPE))
{
//Escape key pressed
}
On Linux you probably have to just use _getch( void ); but I'm not familiar with that.

Related

How exactly do you read a carriage return in c++ e.g as a flag to continue the program

My program has no problems detecting space which i store in a character variable. The program returns zero but does not return one.
edit: changed '/n' to '\n' (typed wrong escape sequence for a new line)
Also my question does not relate to the suggested question: std::cin:: and why a newline remains
because that question is about a stray new line sequence in buffer as per my understanding while i simply demonstrated my failed attempt at trying to store an enter key in a char variable and using an if statement as a flag to detect an enter key.
This set up now works with the flag outputting one. However, I am still keen on learning new ways to store an enter key into a variable so that i can detect it via a flag or any other setup.
#include <iostream>
using namespace std;
int main()
{
char a;
cin.get(a);
if(a=='\n')
cout<<"one";
if(a==' ')
cout<<"zero";
return 0;
}

what happend when I close the buffer of stdin and ungetc to stdin?

It came into my mind when I was reading a book about programming on linux, I tried it on my computer and the code worked fine, but I just could not understand how it worked like that, hope someone could help me explain it, thanks in advance!
my code is as below:
#include <iostream>
#include <cstdio>
using namespace std;
int main() {
setbuf(stdin, NULL);
unsigned char ch = 'a';
unsigned char pch = ungetc(ch, stdin);
char c = getchar();
putchar(c);
return 0;
}
Regardless of buffer setting, ungetc must always be able to push one character back into the input stream. If you attempt to push more than one character, ungetc may fail. (You should check the return value for failure.)
One character of pushback is guaranteed. If the ungetc function is called too many times on the same stream without an intervening read or file positioning operation on that stream, the operation may fail. (ยง7.21.7.10/para. 3)
So a single ungetc is valid, even if there is no input buffer.

C++: cin.peek(), cin >> char, cin.get(char)

I've got this code with use of cin.peek() method. I noticed strange behaviour, when input to program looks like qwertyu$[Enter] everything works fine, but when it looks like qwerty[Enter]$ it works only when I type double dollar sign qwerty[Enter]$$. On the other hand when I use cin.get(char) everything works also fine.
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
char ch;
int count = 0;
while ( cin.peek() != '$' )
{
cin >> ch; //cin.get(ch);
count++;
}
cout << count << " liter(a/y)\n";
system("pause");
return 0;
}
//Input:
// qwerty$<Enter> It's ok
//////////////////////////
//qwerty<Enter>
//$ Doesn't work
/////////////////////////////
//qwerty<Enter>
//$$ works(?)
It's because your program won't get input from the console until the user presses the ENTER key (and then it won't see anything typed on the next line until ENTER is pressed again, and so on). This is normal behavior, there's nothing you can do about it. If you want more control, create a UI.
Honestly I don't think the currently accepted answer is that good.
Hmm looking at it again I think since, operator<< is a formatted input command, and get() a plain binary, the formatted version could be waiting for more input than one character to do some formatting magic.
I presume it is way more complicated than get() if you look what it can do. I think >> will hang until it is absolutely sure it read a char according to all the flags set, and then will return. Hence it can wait for more input than just one character. For example you can specify skipws.
It clearly would need to peek into more than once character of input to get a char from \t\t\t test.
I think get() is unaffected by such flags and will just extract a character from a string, that is why it is easier for get() to behave in non-blocking fashion.
The reason why consider the currently accepted answer wrong is because it states that the program will not get any input until [enter] or some other flush-like thing. In my opinion this is obviously not the case since get() version works. Why would it, if it did not get the input?
It probably still can block due to buffering, but I think it far less likely, and it is not the case in your example.

c++ isalnum endless loop

Greetings!
Lets cut the excessive intro this time and get straight to the point.
I have a problem in C++ using the isalnum method.
the code:
int playAgainst = 0;
do
{
cout << "Who do you want to play against?(1/2)\n";
cout << "1: Human player\n";
cout << "2: Computer player\n";
cin >> playAgainst
} while(!isalnum(playAgainst) && playAgainst != 0);
As seen in the code, I'm providing the user with a choice. Play against human or play against a computer.
What I want is, as long as the user enters anything else then an integer value(cin >> playAgainst) to repeat the question. However, If i enter a char, or string value, it keeps looping endlessly. I am not 100% sure, but it would be obvious, if the problem is, that the non int value is already saved as the value for playAgainst.. How can I check in this bit of code if the input value is int before saving it?
Or is the only possibility to save as a char/string and then check?
If the latter is the case, a new problem arises. isalnum only accepts int as parameter, atleast from what I know. How will I check if that string or char is an int?
Thank you for taking the time to read. And hopefully Ill be accepting a reply as answer soon ^^
Thanks everyone for the answers.
I have gotten what I wanted, and everything has been solved.
The reason I chose for the accepted answer, is well... because initially, it made my code work the way I want it to. I want to accept multiple answers though..
Make playAgainst a char and compare against '0', not 0. Right now, the user has to enter the ASCII (or whatever your character set is) code for the character '1' or '2'.
isalnum won't work on ints outside the valid range of char, except for EOF. (The fact that it takes an int argument is a leftover from C, which has different integer promotions rules than C++. to accomodate for EOF.)
Remove the isalnum() check. cin >> playAgainst will convert anything except a number to zero, which will be caught by the second check. Note that this is only an option because zero is not a valid input.
isalnum() is useful if you're interpreting the characters yourself, but in this case the stream has already done that for you.
This is how the compiler will implement isalnum:
int isalnum (int ch)
{
return (ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9');
}
So you might as well write that code snippet in your own code, and it will be equivalent with an inlined version of isalnum.
It's because you don't clear the buffer. When the input is invalid, you need to clear it from the buffer, and then you can move on to the next input, else you're trying to extract the same input every time (which fails, because it's the same bad input), and thus enter an infinite loop.
The problem is that you're inputing an int, and not a char. And if the
text in the input isn't an int, then the input fails. In which case,
playAgainst isn't modified, and the failure is memorized in std::cin
until you explicitly clear the error. And inputting from a stream in an
error state is a no-op. What you probably want to do is
Input a single character: if you don't want to skip spaces, using
`std::cin.get( ch )` or `ch = std::cin.get()`. (In the latter
case, `ch` should be an `int`, since it must also handle `EOF`.
On the other hand, you can use `::isalnum` on it directly, which
you can't do if `ch` is a `char`.
Fully check for valid input: not just `::isalnum`, but rather
whether the input is a legal selector in your list. Something
along the lines of:
ch != EOF && std::find( legalChars.begin(), legalChars.end(), (char)ch ) != legalChars.end()
In case of error, clear any remaining input, say with:
std::cin.ignore(INT_MAX, '\n');
In practice, you'll probably want to treat EOF differently from
an erroneous command. (If you don't clear the input after EOF, you
won't be able to read anything else. But presumably, if you got EOF,
it's because the user gave up, and doesn't want to try any more.)
Finally, it's probably preferrable to keep all of the information in
a common location, using a table of:
struct Command
{
char op;
char const* prompt;
void (* func)();
};
You then loop over a table of these to output the prompt, search it to
see if the character was legal, and finally, call the function on the
entry you found. Or define an abstract base class, a concrete class
deriving from it for each command, and use an std::map<char,
AbstractBase*> for the mapping, etc. Very C++, but perhaps a bit
overkill for such a simple case.
Why not use isdigit().

Return value of ifstream.peek() when it reaches the end of the file

I was looking at this article on Cplusplus.com, http://www.cplusplus.com/reference/iostream/istream/peek/
I'm still not sure what peek() returns if it reaches the end of the file.
In my code, a part of the program is supposed to run as long as this statement is true
(sourcefile.peek() != EOF)
where sourcefile is my ifstream.
However, it never stops looping, even though it has reached the end of the file.
Does EOF not mean "End of File"? Or was I using it wrong?
Consulting the Standard,
Returns:traits::eof() ifgood()isfalse. Otherwise,returnsrdbuf()->sgetc().
As for sgetc(),
Returns: If the input sequence read position is not available, returns underflow().
And underflow,
If the pending sequence is null then the function returns traits::eof() to indicate failure.
So yep, returns EOF on end of file.
An easier way to tell is that it returns int_type. Since the values of int_type are just those of char_type plus EOF, it would probably return char_type if EOF weren't possible.
As others mentioned, peek doesn't advance the file position. It's generally easiest and best to just loop on while ( input_stream ) and let failure to obtain additional input kill the parsing process.
Things that come to mind (without seeing your code).
EOF could be defined differently than you expect
sourcefile.peek() doesn't advance the file pointer. Are you advancing it manually somehow, or are you perhaps constantly looking at the same character?
EOF is for the older C-style functions. You should use istream::traits_type::eof().
Edit: viewing the comments convinces me that istream::traits_type::eof() is guaranteed to return the same value as EOF, unless by chance EOF has been redefined in the context of your source block. While the advice is still OK, this is not the answer to the question as posted.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//myifstream_peek1.cpp
int main()
{
char ch1, ch2;
ifstream readtext2;
readtext2.open("mypeek.txt");
while(readtext2.good())
{
if(readtext2.good())
{
ch2 = readtext2.get(); cout<< ch2;
}
}
readtext2.close();
//
ifstream readtext1;
readtext1.open("mypeek.txt");
while(readtext1.good())
{
if(readtext1.good())
{
ch2 = readtext1.get();
if(ch2 ==';')
{
ch1= readtext1.peek();
cout<<ch1; exit(1);
}
else { cout<<ch2; }
}
}
cout<<"\n end of ifstream peeking";
readtext1.close();
return 0;
}
While this technically works, using ifstream::eof() would be preferable
as in
(!sourcefile.eof())