Why if(!cin.get(ch)) condition does not result true when we enter ctrl+z?

Hello all,

In this code I want whenever the use entered the "ctlr+z" whether first or after entering some characters, the program calls the error() function as defined below.
when I enter computer followed by ctrl+z the if(!cin.get(ch)) condition should result true (after pasing c o m p u t e r characters and facing to last ctrl+z and then call the error(....) function (line 18) and the program should terminate. But it does not do that!!!
Does anyone know why?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class Book {
public:
	void TITLE();
	string Title() { return title; }
private:
	string title;
};

//***************************************

void Book::TITLE() {
	cout << "Enter the Title of the BOOK followed by Enter: ";
	string s;
	char ch;
	while((cin.get(ch)) && (ch == ' ' || ch == '\n'));
	cin.putback(ch);
	do {
	if(!cin.get(ch)) error ("\nBad name for Title (it's empty)");
		 s += ch;
	} while(ch != '\n');
		title = s;
}

//***************************************

int main()
try {
	Book b1;
	b1.TITLE();
	cout << " \nThis BOOK is:\n" << b1.Title();
	getch();
	return 0;
}
catch (exception& e) {
	cerr << e.what() << "!!!\n	program will terminate after you press a key...";
	getch();
	return 0;
}
If cin.get(ch) fails it leaves ch unmodified. On line 16 when you put ch back in cin, ch can be uninitialized if it failed to read any character, otherwise it will put back the last character that was successfully read. In the case when you enter computer and press ctrl+z it will put the char 'r' back in cin. In the loop that follows it will read 'r' again in the first iteration, and fail in the second iteration but that will not modify ch so it never escapes the loop because ch will always be 'r'.
Last edited on

Thank you for your help trying. But consider somethings:

When we enter computer, the first c character passes from first while(.. loop in line 15, and notice that loop doesn't have any statement, there is a ';' right after that loop.

So cin.putback(ch) in line 16 puts back it into cin. Then (into do{ }while(); loop), the if(!cin.get(ch)) condition reads that c and then the loop continues and in each iteration that condition checks tor the success of cin.get.
For the c till r characters the result isn't true but when we enter ctrl+z at the last, it should result true and then the error function be called. But it doesn't!
As little as I know about Windows, Ctrl+Z only closes the standard input if typed on a line of its own, followed by Enter, not when it follows some other letters on a line of input.
If you enter computer 'c' will never be put back into cin because the loop on line 15 runs until it fails to read a character or it finds a space or newline character.
Last edited on
Thank you cubbi, your talk may be right and the real reason of my problem.
But anyway, I try to get the exactly real reason.

And about dear peter. We now get the program the c character to see whether it never put back!!

The code snip is while((cin.get(ch)) && (ch == ' ' || ch == '\n'));
we input c, so the code will be while((1) && ( 0 || 0)); So the result is failure for that loop and then cin.putback(ch) in line 16 puts back that c, not?

As it's clear, in above loop, the result of cin.get(ch) is true because it succeeded to get a character, here a c, and because the c is not a space or new line so the right hand condition of && will be false, so the entire result is false. And then that c will passes from the loop and goes to cin.putback(ch) function in line 16.
Attention to parentheses.
Yeah, you are right. I was wrong.
Do the semicolons after the while and if statements (lines 15 & 18) produce unwanted effects?
Do the semicolons after the while & if statements (on lines 15 & 18) cause unwanted effects?
No, I don't think. The semicolon after while... loop (line 15) is what I wanted and is correct.
The semicolon in line 18 is not the if statement semicolon! It's the last necessary character for statements, here error(....) function statement.
Thank you very much for trying to help me.

Any other opinion will be warmly welcome to help me.
Last edited on
I should have known .... If Cubbi & Eagle Eyed Peter87 hadn't said anything .....

Out of respect, I am wary of pointing out minor details to those who know much more than me, but nonetheless I would point out the following 2 trivial things:

1: I would have done this - to show it was on purpose

1
2
while((cin.get(ch)) && (ch == ' ' || ch == '\n'))
        ;  //null statement 


2: I always put braces - even if it is 1 statement, and I never put 2 statements on 1 line:

1
2
3
if(!cin.get(ch)) {
      error ("\nBad name for Title (it's empty)");
}


or even this:

if(!cin.get(ch)) { error ("\nBad name for Title (it's empty)");}

With the original code, for me it was too easy to miss the space between the condition and the next statement. The braces would have caught my eye.

Anyway, I have been promising myself to learn to read properly ! :-)

Last edited on
As I think you know, the braces aren't needed for one statement of if. Trust the compiler! It's better.

All guys please put your opinions about the cubbi's comment, "In Windows, Ctrl+Z only closes the standard input if typed on a line of its own, followed by Enter, not when it follows some other letters on a line of input."

Thanks in advance!
Last edited on
@TheIdeasMan @khoshtip
Always use braces. ALWAYS. Make it obvious that no code needs to be executed:
1
2
3
    while(/*something*/)
    {
    }
Also, always write the parenthesis and braces before filling them in.
Last edited on
@khoshtip

As I think you know, the braces aren't needed for one statement of if. Trust the compiler! It's better.


The reason I always use braces (even for 1 statement), is because it will save me one day when I add more code. L B's idea for null statements is better.

Sure, I can trust the compiler, but it's humans that cause problems!! Ideas that we are talking about, are designed to help prevent problems. It's better to prefer methods like this rather than something that might lead to problems.

I don't know anything about Windows & Ctrl-Z. I know this much though - cubbi does know what he is talking about. If no one has said anything after this amount of time, then I would suggest that he is right. cubbi seems very rarely to be wrong (if at all), he is a software engineer after all.

@L B

Yes, I can see that the braces are more obvious than the null statement comment. Thanks for that.

My IDE does closing braces, parentheses & chevrons automatically, so I had to train myself not to type the closing brace straight away, after having done this for the last 25 years. Lisp programming with an ordinary editor teaches one these old techniques.
I finally got to a Windows and tested:

^Z<enter> at the beginning of a line closes cin (moves it to end-of-file state) and does not result in any character reads. Clearing eofbit and reading again continues input from cin (it doesn't on some platforms).
^Z in the middle of the line results in the read of the character 0x1a and discards the rest of the line (so 'ab^Zcd<Enter>' reads 'a', 'b', and '\x1a' only)

this is somewhat similar to your typical unix-ish ^D behavior, except that ^D never sends any characters and acts immediately (doesn't need an enter)
Last edited on
@TheIdeasMan and @L B

Although I probably disagree with this style but anyway, I COMPLETELY respect your habits.

I think finally we, (of course me!) can achieve the reason of that unplausible result of the compiler for that code. I two days ago tested the code by step debugger (F10 in MVStudio IDE) and saw the compiler names of characters like ^Z and so on that resulted in '\x1a' for that and ...
I think the last step is to finding out what will happen (what the compiler will respond) when we enter "computer^Z" and what for "^Zcomputer" and what for "com^Zputer".
unfortunately I don't have the IDE for testing those states and showing the result for all of us (especially for myself!) in this machine (this one that now I'm typing his comment) and should wait till tomorrow to going to office and get my main machine.

@cubbi

First off thank you for your help.
And then:
I think one or more states (of mixing the ^Z with the string, e.g., "computer") is missing.
With respect to you, but please don't complex the issue by adding the result states of another OSs for ^Z.
Thanks again.
Last edited on
When we enter ^Z or ^Zcomputer, the output is the calling of error(....) function. And when we enter comp^Zuter or computer^Z the output is comp-> or computer->. So apparently the result in Windows is:

Ctrl+Z only closes the standard input if be the first typed character whether it be followed by other characters or be alone, and then followed by Enter.
Topic archived. No new replies allowed.