Clarification needed regarding getchar() and newline - c++

I have a doubt regarding using getchar() to read a character input from the user.
char char1, char2;
char1 = getchar();
char2 = getchar();
I need to get 2 chars as inputs from the user. In this case, if the user enters the character 'A' followed by a newline, and then the character 'B', what will be stored in char2 - will it be the newline character or the character 'B'?
I tried it on CodeBlocks on Windows, and char2 actually stores the newline character, but I intended it to store the character 'B'.
I just want to know what the expected behavior is, and whether it is compiler-dependent? If so, what differences hold between turbo C and mingW?

Yes, you have to consume newlines after each input:
char1 = getchar();
getchar(); // To consume `\n`
char2 = getchar();
getchar(); // To consume `\n`
This is not compiler-dependent. This is true for all platforms as there'll be carriage return at the end of each input line (Although the actual line feed may vary across platforms).

I just want to know what the expected behavior is, and whether it depends on the compiler-dependent?
That's the expected behavior and not compiler-dependent.
You can use scanf to read A followed by newline, then B followed by newline. If you want to stick to getchar(), then simply give the input as AB.

You can prevent reading newlines by explicitly testing for it.
Instead of simply using
getchar():
you can use something like this
while((char1 = getchar()) == '\n');
If you're on windows you might want to test for '\r' too. So the code changes a little.
while((char1 = getchar()) == '\n' || char1 == '\r');

add statement fflush(stdin); in between statements.
look this one
ch1=getchar();
fflush(stdin);
ch2=getchar();

Related

Scanf does not work as expected

I tried to compare std::cin and scanf, I expected them to have same behavior, but actually not:
#include<iostream>
using namespace std;
int main()
{
int i;
cin>>i;
return 0;
}
This receives an input from user, no problem.
But
#include<stdio.h>
int main()
{
int i;
scanf("%d\n",&i);
return 0;
}
I input a integer, program doesn't terminate even if I press "enter" multiple times, unless I enter another integer number.
Note there's an "\n" in scanf's format string.
So I tried to add one statement
printf("%d\n", i);
Well it prints out the 1st number I just input. This is correct but weird, why after scanf, the program requires me to enter any character rather then \n, to exit the program?
I tried both VC and GCC, same problem. What is that \n indicating?
scanf("%d\n",&i);
Let's read the manpage of scanf :
Whitespace character: the function will read and ignore any whitespace characters encountered before the next non-whitespace character (whitespace characters include spaces, newline and tab characters -- see isspace). A single whitespace in the format string validates any quantity of whitespace characters extracted from the stream (including none).
What it means is scanf will search for a integer followed by an optionnal whitespace. that's why he's waiting for you to use two times enter. If you used "%d\n\n", it'll have to be three times. And so on.
If you want only an interger, use scanf("%d",&i);
scanf("%d\n",&i); is equivalent to std::cin >> i >> std::ws;.
If you want the same behaviour for scanf, remove \n: scanf("%d",&i);
This is caused by the fact that any whitespace character in scanf means "skip input until non-whitespace is found"

Checking if a char is a newline

I'm doing an exercise in C++ Primer and basically I am using a switch statement to count the number of vowels in a text that I input.
I input the text using a while loop.
while(cin >> ch)
and proceed with the cases, a, e, i, o, u, incrementing an integer variable for the respective cases. Now the next part of the question says also count the spaces, tabs and newlines.
I tried doing
case ' ':
and so forth using '\t' and '\n'. But it seems like it doesn't compute these cases. I also tried just using a default and using an if else statement
default:
if(ch == ' ')
++space;
etc. But this doesn't proceed either. I also tried putting in the integer values of ' ', '\t', '\n'. What am I doing wrong here? Also, I know that if I use isspace() I can count the combined total but I need to compute each one individually. I'm not sure why the equality test won't do the job.
By default, formatted input from streams skips leading whitespace. You need to either disable skipping of leading whitespaces or use one of the functions which won't skip spaces:
std::cin >> std::noskipws; // disables skipping of leading whitespace
char c;
while (std::cin.get(c)) { // doesn't skip whitespace anyway
...
}
As said by Dietmar, white spaces are skipped by default. You could use cin.getline() to provide your own string delimiter instead of white space characters. I would say this is a generally easier way of reading input compared to using cin.get().

How does input buffering work in C++

Here is a code snippet. I'm confused as to how the buffering internally works.
while(true)
{
cout << "Enter a character: ";
cin.ignore(3, '\n');
ch = cin.get(); // ch is char type
cout << "char: ch: " << ch << endl;
}
Actually cin.ignore(3, '\n') ignores the first three characters and then gets the next immediate character. Till that point its fine. Since, I kept this in a while loop, I was trying to check the behavior of ignore() and get(). For instance, the output for which I checked was
Enter a character: abcd
char: ch: d
Enter a character: efgh
char: ch: e
Enter a character: ijkl
char: ch: i
Enter a character: mnopq
char: ch: m
Enter a character: char: ch: q
Enter a character:
Just to check the buffering, intentionally I was give 4 characters instead of 1. In the first case, its fine and got it. From second, the ignore doesn't seem to work. When I entered 5 characters, I din't get the behavior.
Need explanation on this. :)
According to documentation of std::cin.ignore(streamsize n = 1, int delim = EOF):
Extracts characters from the input sequence and discards them, until either n characters have been extracted, or one compares equal to delim.
http://www.cplusplus.com/reference/istream/istream/ignore/
You are putting abcd\n onto stdin. Your first ignore(3,'\n') removes abc and your get() fetches d. \n remains in the buffer.
Then you add efgh\n to the buffer which now contains \nefgh\n. Your next ignore() reads either 3 characters or a newline, whatever comes first. Since your newline is first in the buffer, only the newline is ignored.
You probably want to empty the stdin buffer before asking for more input. You can achieve this either by modifying your get() call, or by adding a second ignore() call before asking for more input.
cin.ignore(3, '\n') ignores up to three characters, stopping after it finds the end of a line (i.e. a \n character).
After the first line of input, the buffer will contain 5 characters, abcd\n. So ignore ignores abc, and get gets d, leaving \n.
After the second line, it contains \nefgh\n. So ignore just ignores the end-of-line character, and get returns e.
If you want to discard the rest of line after extracting the character, then use ignore again:
cin.ignore(numeric_limits<streamsize>::max(), '\n');

istream and cin.get()

I have a question about the difference between these two pieces of code:
char buffer5[5];
cin.get(buffer5, 5);
cout << buffer5;
cin.get(buffer5, 5);
cout << buffer5;
and
char buffer4;
while (cin.get(buffer4))
{
cout << buffer4;
}
In the first piece of code, the code gets 5 characters and puts it in buffer5. However, because you press enter, a newline character isn't put into the stream when calling get(), so the program will terminate and will not ask you for another round of 5 characters.
In the second piece of code, cin.get() waits for input to the input stream, so the loop doesn't just terminate (I think). Lets say I input "Apple" into the input stream. This will put 5 characters into the input stream, and the loop will print all characters to the output. However, unlike the first piece of code, it does not stop, even after two inputs as I can continuously keep inputting.
Why is it that I can continuously input character sequences into the terminal in the second piece of code and not the first?
First off, "pressing enter" has no special meaning to the IOStreams beyond entering a newline character (\n) into the input sequence (note, when using text streams the platform specific end of line sequences are transformed into a single newline character). When entering data on a console, the data is normally line buffered by the console and only forwarded to the program when pressing enter (typically this can be turned off but the details of this are platform specific and irrelevant to this question anyway).
With this out of the way lets turn our attention to the behavior of s.get(buffer, n) for an std::istream s and a pointer to an array of at least n characters buffer. The description of what this does is quite trivial: it calls s.get(buffer, n, s.widen('\n')). Since we are talking about std::istream and you probably haven't changed the std::locale we can assume that s.widen('\n') just returns '\n', i.e., the call is equivalent to s.get(buffer, n, '\n') where '\n' is called a delimiter and the question becomes what this function does.
Well, this function extracts up to m = 0 < n? n - 1: 0 characters, stopping when either m is reached or when the next character is identical to the delimiter which is left in the stream (you'd used std::istream::getline() if you'd wanted the delimiter to be extracted). Any extracted character is stored in the corresponding location of buffer and if 0 < n a null character is stored into location buffer[n - 1]. In case, if no character is extracted std::ios_base::failbit is set.
OK, with this we should have all ingredients to the riddle in place: When you entered at least one character but less than 5 characters the first call to get() succeeded and left the newline character as next character in the buffer. The next attempt to get() more characters immediately found the delimiter, stored no character, and indicated failure by setting std::ios_base::failbit. It is easy to verify this theory:
#include <iostream>
int main()
{
char buffer[5];
for (int count(0); std::cin; ++count) {
if (std::cin.get(buffer, 5)) {
std::cout << "get[" << count << "]='" << buffer << "'\n";
}
else {
std::cout << "get[" << count << "] failed\n";
}
}
}
If you enter no character, the first call to std::cin.get() fails. If you enter 1 to 4 characters, the first call succeeds but the second one fails. If you enter more than 4 characters, the second call also succeeds, etc. There are several ways to deal with the potentially stuck newline character:
Just use std::istream::getline() which behaves the same as std::istream::get() but also extracts the delimiter if this is why it stopped reading. This may chop one line into multiple reads, however, which may or may not be desired.
To avoid the limitation of a fixed line length, you could use std::getline() together with an std::string (i.e., std::getline(std::cin, string)).
After a successful get() you could check if the next character is a newline using std::istream::peek() and std::istream::ignore() it when necessary.
Which of these approaches meets your needs depends on what you are trying to achieve.

C++: Using cin.getline()

Now I have learned that cin.getline works like this.
cin.getline(dest string, number of charecters to put into string);
so assume this program.
char s1[8]="Hellopo";
cin.getline(s1,5);
cout<<s1<<endl;
This was by input :hhhhhhhhhhhhh
This was the programs output: hhhh
I have 2 concerns in this program.
1-) I set the program to get 5 characters from what the user inputed and store in s1. When I ran The program it only printed out 4 characters.
2-) Also I expected the program to continue printing out the rest of s1 after it printed out what it got from the user. but it stopped after hhhh
Please explain to me my two concerns. Thank you
std::cin::getline will store four characters plus a null termination in this case (five characters in total). And std::cout will stop printing at the first null terminator it finds.
From istream::getline():
count-1 characters have been extracted (in which case setstate(failbit) is executed).
This means that if you specify 5, only 4 characters will be read. And:
...it then stores a null character CharT() into the next successive location of the array
so a null character will be inserted after the fourth character. So the array s will have contents:
'h' == s[0]
'h' == s[1]
'h' == s[2]
'h' == s[3]
0 == s[4]
The operator<< will stop printing a char* when the first null character is found.
The fifth character is the 0-terminator. getline(buffer,n) stores up to n bytes including the 0-terminator in the buffer. And then cout << s1; stops at the 0-terminator.
The fifth character is the null terminator, which marks the end of the string.