Getline keeps on getting newline character. How can I avoid this? - c++

Basically I first takes an integer as input and then test case follows. My each test case is an string. I am suppose to print the string back if the starting patten of string matches "HI A" and it is case-insensitive. I wrote the code below to accomplish to this. My problem is that when I press enter after each input, getline takes newline character as new input. I have tried to tackle this by using extra getline after each input but the issue is still there. Program gets stuck in the loop even though I have put a break condition. What am I doing wrong?
#include <iostream>
#include <string>
using namespace std;
int main(){
int N;
cin >>N;
string nl;
getline(cin,nl);
for (int i=0;i<N;i++){
string s;
getline(cin,s);
//cout <<"string"<<s<<endl;
int flag=0;
if ((s.at(0)=='h'||s.at(0)=='H')&&(s.at(1)=='i'||s.at(1)=='I')&&(s.at(2)==' ')&&(s.at(3)=='a'||s.at(3)=='A')) flag=1;
if (flag==1) cout << s;
//cout << "not " <<s;
string ne;
cout << "i="<< i<<endl;
if (i==N-1) {break;}
getline(cin,ne);
}
}
Here is sample input:
5
Hi Alex how are you doing
hI dave how are you doing
Good by Alex
hidden agenda
Alex greeted Martha by saying Hi Martha
Output should be:
Hi Alex how are you doing

ignore() function does the trick. By default, it discards all the input suquences till new line character.
Other dilimiters and char limit can be specified as well.
http://www.cplusplus.com/reference/istream/istream/ignore/
In your case it goes like this.
cin >> N;
cin.ignore();

Your cin >>N stops at the first non-numeric character, which is the newline. This you have a getline to read past it, that's good.
Each additional getline after that reads the entire line, including the newline at the end. By putting in a second getline you're skipping half your input.

So, your real problem isn't that getline eats newlines, but that your second getline(cin, ne) is eating a line...
And that is because you mistakenly think that you need two getline operations to read one line - or something like that. Mixing "linebased" and "itembased" input does have confusing ways to deal with newlines, so you do need something to "skip" the newline left behind frin cin >> N;, but once you have got rid of that, you only need ONE getline to read up and including the newline at the end of a line.

I am writing this answer with the hopes that it may help someone else out there that wants a very simple solution to this problem.
In my case the problem was due to some files having different line endings such as '\r' vs. '\n'. Everything worked fine in windows but then it failed in Linux.
The answer was actually simple. I created a function removeNewLineChar after each line was read in. That way the char was removed. The removeNewLineChar takes in the line that was read in and copies it over character by character into a new string but it avoids copying either of the newline characters.
Here is an example:
string trim(string line)
{
string newString;
for (char ch : line)
{
if (ch == '\n' || ch == '\r')
continue;
newString += ch;
}
return newString;
}
//some function reading a file
while (getline(fin, line)) {
line = trim(line);
//... do something with the line
line = "";
}

you just need to accept the fact that getline will give you '\n' at the end. One solution is remove '\n' after getting it. Another solution is do not write the additional 'endl'. for example, for your problem, you can use this code
int N;
cin >> N;
string line;
getline(cin, line); // skip the first new line after N.
for (int i = 0; i < N; i++) {
string line;
getline(cin, line);
string first4 = line.substr(0, 4);
// convert to upper case.
std::transform(first4.begin(), first4.end(), first4.begin(), std::ptr_fun<int, int>(std::toupper)); // see http://en.cppreference.com/w/cpp/algorithm/transform
if (first4 == "HI A") {
cout << line; // do not include "<< endl"
}
}

cin.ignore() worked for me.
void House::provideRoomName()
{
int noOfRooms;
cout<<"Enter the number of Rooms::";
cin>>noOfRooms;
cout<<endl;
cout<<"Enter name of the Rooms::"<<endl;
cin.ignore();
for(int i=1; i<=noOfRooms; i++)
{
std::string l_roomName;
cout<<"Room"<<"["<<i<<"] Name::";
std::getline(std::cin, l_roomName);
}
}

std::string line;
std::cin>>std::ws; // discard new line not processed by cin
std::getline(std::cin,line);
From Notes section https://en.cppreference.com/w/cpp/string/basic_string/getline
When consuming whitespace-delimited input (e.g. int n; std::cin >> n;) any whitespace that follows, including a newline character, will be left on the input stream. Then when switching to line-oriented input, the first line retrieved with getline will be just that whitespace. In the likely case that this is unwanted behaviour, possible solutions include:
An explicit extraneous initial call to getline
Removing consecutive whitespace with std::cin >> std::ws
Ignoring all leftover characters on the line of input with cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

Related

Does getline() not extract the delimiter?

So I was taking input some integers and then taking input some sentences.
This code works fine:
#include<bits/stdc++.h>
using namespace std;
main(){
int c,b,n,i;string s;
cin>>n>>b>>c;
for(i=0;i<n;i++){
cin>>ws;
getline(cin,s,'\n');
cout<<s;
}
}
Example:
3 3 3
This is weird
This is weirdDefinitely makes
Definitely makesNo sense
No sense
However, when I try to omit the cin>>ws inside the forloop, it doesn't work properly, eg this code segment,
#include<bits/stdc++.h>
using namespace std;
main(){
int c,b,n,i;string s;
cin>>n>>b>>c;
for(i=0;i<n;i++){
getline(cin,s,'\n');
cout<<s;
}
}
Example:
3 3 3
This is weird
This is weirdDefinitely makes
Definitely makes
..and terminates there instead of taking all three inputs.
Why is that? cin>>ws extracts all whitespace from the input but isn't getline() doing that too? So why does it not work properly when I omit cin>>ws in the forloop?
std::getline() extract characters until it extracted the first delimiter character (by default '\n'). The delimiter is not stored in the result but it is extracted. It does not extract whitespace in general or multiple delimiter characters.
As an aside: always check whether input works after trying to read a value.
In the example printed, the issue is is that after formatted input, i.e., using the >> operator, whitespaces are not extracted. That is, the first calls to std::getline() extracts the empty string terminated by the initial newline. It generally is necessary to extract trailing whitespace when switching between formatted and unformatted I/O. That is, You'd want code like
if (cin>>n>>b>>c >> std::ws) {
for(i=0;i<n;i++){
if (getline(cin,s,'\n')) {
cout << "i=" << i << ":'" << s << "'\n";
}
}
}
I can't recommend input operations without adding check for success. The output is changed to make it more easily visible what is going on: try the code with/without this particular std::endl to see what is happening.
When you use cin >> it doesn't remove any whitespace after the input. This means the newline that terminated the first 3 inputs is still in the buffer, waiting to be read by the first getline. Since there's nothing before the newline, the first getline delivered an empty string. Your output should have included a newline so you could have seen the empty line, then it would have made sense.
Originally the code you posted showed a cin >> ws just before the for loop which would have eliminated this problem.
The default delimiter for getline() is '\n', so there is no need to include that in the getline call, though, it should not change the functionality.
See for example Same as getline(input, str, input.widen('\n')), that is, the default delimiter is the endline character.
The change in formatting from the integer input to the getline() input leaves some whitespace (endl) after the integer as explained by #DietmarKühl.
You can change the getline() call to eliminate the delimiter to
getline(cin,s);
which will cause getline() to use '\n' as the default delimiter.
I have modified the 'n' variable to count and removed the other integers to make the code a little simpler to read:
#include <iostream>
int main()
{
int i; // index
int count; // number of strings to accept
std::string str;
std::cout << "Input the number of strings you would like me to process: " << std::endl;
std::cin >> count;
if (std::cin >> count >> std::ws) {
for (i = 0; i < count; i++) {
if (getline(std::cin, str)) {
std::cout << "i=" << i << ":'" << str << "'\n";
}
}
}
}
Cin doesn't extract all white spaces, it just gets the first word until the first white space. It is like having a getline with a space delimiter(not quite but close to).
Getline takes the whole line and has the default '\n' delimiter like mentioned above.
Ex:
string a = "Stack Overflow is awesome";
can give you Stack and getline will give you everything at that line

Error while using getline() in c++

I am using getline to read strings and print but while using that I am unable to give input so I used ignore()
Code
int t;
cin>>t;
string str;
for(int i=0;i<t;i++)
{ cin.ignore();
getline (cin, str);//reading string
cout << str << endl;
}
return 0;
When using that while printing output every first character from second line of output are missing?
The std::getline function reads (but doesn't store) the newline, so in the second (and every following) iteration of the loop your call to ignore will read the first character of that line.
You should move the ignore call to before the loop.

Reading sentences as string inputs from users

I have been trying to implement a simple code which takes a sentence as an input from the user, stores it in a string and displays it back.
Here are the issues:
1. When T = 1, the program exits immediately.
2. When T>1, the loop runs for only T-1 times.
I think the usage of cin to store the value of T is an issue here. Is the value of T entered being stored as a string due to some buffer capacity of cin?
#include <iostream>
#include <string>
int main()
{
int T;
std::cin >> T;
while (T--)
{
std::string song;
getline(std::cin, song);
std::cout << song << std::endl;
}
return 0;
}
How do you terminate the input that becomes T? With a newline. What happens with that newline after you read into T? It's still left in the input buffer. What will happen when you next call std::getline, what is the first character it will read? The newline, and what happens next? The loop iterates and then T is zero (for the first case where T was originally 1) and the loop and then the program exits.
The solution to this problem is to ignore characters up to and including the newline.
Add a getchar after cin as the \n after the input of T stays in buffer.
std::cin >> T;
getchar();
This is a strange way to do it. So you ask the user to tell the program, before any other input, how many lines will follow? Why not simply:
std::string s;
while (getline(std::cin, s)) {
std::cout << s << std::endl;
}
(This will simply echo every line (press enter to end the line) until end-of-file (Ctrl-d).
Either way, the problem with your code is the while (T--): so why don't you try to see what your T is, and what your getline gives you on each iteration? (I will let you figure it out on your own). Why not use the idiomatic:
for (int i = 0; i < T; ++i)
?
P.S. If you want to read sentences, and not lines, you might want to consider reading up to a delimiter (for example .). getline will do that for you, too:
getline(std::cin, s, '.');

getline is not waiting for the input

I am trying to read the n-th line from the standard input in the following program. However, the console will print out "current line is" before I input any number...not sure what's wrong. Thanks for help.
int main()
{
string currentLine;
int n;
cin >> n;
cout << n << endl;
while (n > 0)
{
getline(cin, currentLine);
cout << "current line is" << currentLine << endl;
n--;
}
return 0;
}
The formatted input using operator>>() stops as soon as its format can't be satisfied by the next character. For integers it stops when there is no further digit, e.g., when the next character is a whitespace like the newline from entering the line.
std::getline() reads until it finds the first newline. There was one left right before when reading the integer. You probably want to extract this newline and potentially other whitespace. You could, e.g., use
if (std::getline(std::cin >> std::ws, currentLine)) {
// do something with the current line
}
else {
// deal with a failure to read another line
}
The manipulator std::ws skips leading whitespace. As indicated above, you should also verify that the input was actually successful before processing input.
In order to get n, you have to input a number and press the Enter button. As #Kuhl said, the operator>> stops as soon as its format can't be satisfied by the next character.
This means the first time getline(cin, currentline) runs will get '\n' !
Then the program will output "current line is\n" while the '\n' will not be shown on the console.
If you want to get n and 'currentline', you may choose the #Kuhl's answer or write the program like this:
getline(cin, currentline);
while(n>0) {
// anything you want
}
The getline(cin, currentline) will help you to skip the '\n' followed by the number 'n'.

C++ getline method not working

I'm sorry but I'm quite new to C++ but not programming in general. So I tried to make a simple encryption/decryption. However when I added the modification to my previous code (so there isn't two programs for encrypting and decrypting) I found that the code 'getline()' method no longer works. Instead it's just ignoring it when the code is ran. Here's the code:
int main(){
std::string string;
int op = 1; //Either Positive or Negative
srand(256);
std::cout << "Enter the operation: " << std::endl;
std::cin >> op;
std::cout << "Enter the string: " << std::endl;
std::getline(std::cin, string); //This is the like that's ignored
for(int i=0; i < string.length(); i++){
string[i] += rand()*op; //If Positive will encrypt if negative then decrypt
}
std::cout << string << std::endl;
std::getchar(); //A Pause
return 0;
}
That's because std::cin >> op; leaves a hanging \n in your code, and that's the first thing getline reads. Since getline stops reading as soon as it finds a newline character, the function returns immediately and doesn't read anything more. You need to ignore this character, for example, by using cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); (std::numeric_limits is defined in header <limits>), as stated on cppreference.
This is because you still have the newline character in the buffer which makes getline() stop reading as soon as it encounters it.
Use cin.ignore() to ignore the newline character from the buffer. This will do in your case.
In general, if you want to remove characters from your buffer untill a specific character, use:
cin.ignore ( std::numeric_limits<std::streamsize>::max(), ch )
Use :
cin.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
to eat newlines from previous input std::cin >> op;
header - <limits>
Other way would be :
while (std::getline(std::cin, str)) //don't use string
if (str != "")
{
//Something good received
break;
}
As other stated already, the formatted input (using in >> value) start skipping space abd stop when they are done. Typically this results in leaving some whitespace around. When switching between formatted and unformatted input you typically want to get rid of leading space. Doing so can easily be done using the std::ws manipulator:
if (std::getline(std::cin >> std::ws, line)) {
...
}
You must use std::cin.ignore() before std::getline(std::cin, string) to clear the buffer, because when you use std::cin >> op before the getline a \n gets in the buffer and std::getline() reads it. std::getline() takes only the line you type, when you skip a line, std::getline() closes, so when std::getline() picks up \n from the buffer it is already terminated before you type something, because /n skips a line.
Try this way:
int main(){
std::string string;
int op = 1; //Either Positive or Negative
srand(256);
std::cout << "Enter the operation: " << std::endl;
std::cin >> op;
std::cout << "Enter the string: " << std::endl;
std::cin.ignore();
std::getline(std::cin, string); //This is the like that's ignored
for(int i=0; i < string.length(); i++){
string[i] += rand()*op; //If Positive will encrypt if negative then decrypt
}
std::cout << string << std::endl;
std::getchar(); //A Pause
return 0;
}