C++ getline method not working - c++

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;
}

Related

Cannot push back a string into a vector of strings c++

I'm trying to create a program to separate a single line into a vector of strings separated by the blank spaces in said line, so turn:
foo bar
into
["foo", "bar"]
This is what I have so far:
string command;
string command_temp;
vector<string> command_seperated;
std::cin >> command;
for (int i = 0; i < command.length(); i++){
if (isspace(command[i])){
cout << "blankspace" << endl; command_seperated.push_back(command_temp);
command_temp.clear();
}
command_temp.push_back(command[i]);
for (int i = 0; i < command_temp.size(); i++){
cout << command_temp[i];
}
cout << endl;
}
for (int i = 0; i < command_seperated.size(); i++){
cout << command_seperated[i] << endl;
}
But, if I input "foo bar" when prompted, this just returns:
foo bar
f
fo
foo
Process returned 0 (0x0) execution time : 2.596 s
Press any key to continue
I assume the reason the last for loop isn't printing anything is that there's nothing in it and the push_back to command_seperated isn't working. I have no idea why.
I also don't know why the entire program seems to just stop working after the first blank space.
Using this to refresh my rudimentary C++ skills, so I would appreciate an explanation of why I'm wrong, rather than a more elegant alternative solution.
What you are seeing is normal behavior of operator>>, which is used for reading formatted input. It skips leading whitespace (if the skipws flag is enabled on the stream, which it normally is), then reads until EOF or whitespace is encountered. So, in your example, std::cin >> command receives only foo even though you entered foo bar. If you invoked std::cin >> command a 2nd time, you would receive bar.
To read a string that contains whitespace in it, use std::getline() instead:
std::getline(std::cin, command);
It does not skip leading whitespace, and reads until EOF or a linebreak (ie, from typing Enter) is encountered.
That being said, the parsing code you have shown can be greatly simplified if you use a std::istringstream with operator>> to parse the command, eg:
std::string command, token;
std::vector<std::string> command_seperated;
std::getline(std::cin, command);
std::istringstream iss(command);
while (iss >> token) {
command_seperated.push_back(token);
}
for (const auto &str : command_seperated){
cout << str << endl;
}

Why is my program getting a runtime error when I execute my code? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
This program is working without the loop, however when I implement the loop, I get a runtime error. I think it might have something to do with my cin.getline but I really have no idea :/ any help would be great thank you!
#include <iostream>
using namespace std;
#include <string>
#include <iomanip>
int main ()
{int ans, z;
z=1;
cout << "How many times would you like to execute this string program? " << endl;
cin >> ans;
while (z <= ans)
{
int x, i, y, v;
string answer1, str3;
string mystring, fname, lname;
i=0;
y=0;
cout << "Please enter your first and last name: ";
getline(cin, answer1);
cout << endl;
x=answer1.length();
for (int i = 0; i < x; i++)
{
cout << answer1[i] << endl;
if (isspace(answer1[i]))
{
y=i;
}
}
cout << endl << endl;
cout << setw(80) << answer1;
mystring = answer1;
v=answer1.find(" ", 0);
fname=mystring.substr(0, y);
lname=mystring.substr(v, x);
cout << "First name: " << fname << endl;
cout << "Last name: " << lname << endl;
mystring=lname+','+fname;
cout << setw(80) << mystring;
z++;
}
return 0;
}
The error happens in this line:
lname=mystring.substr(v, x);
where v happens to have a very large value. So how does your program get there, and how does v get this value? v has value std::string::npos, which is an error code meaning, in this case, that the space you were looking for wasn't there. That this is the case has to do with the difference between formatted and unformatted input and the fact that you're mixing them.
Formatted input means treating an input stream as a stream of tokens. Leading whitespace -- all whitespace, whether space, tab, or newline -- is skipped, and where the token ends, there does the input. One example of formatted input is
cin >> ans;
For formatted input, everything that doesn't fit its pattern looks the same. Whether std::istream::operator>>(int) encounters a space, a tab, a newline, an 'a' or a 'z', that's just the end of the token, and there it stops reading. For example, if you have
int x;
std::string s;
std::cin >> x >> s;
and feed it the input 123abc, then x will have the value 123, and s will be "abc". Crucially, this means that if the user answers
cin >> ans;
with a number and newline, the encountered character after the number -- a newline -- remains in the stream.
Unformatted input, by contrast, means treating an input stream as a stream of characters. For unformatted input functions, whitespaces are just another character, and unless the unformatted input function defines a special meaning for them, it will treat them the same as any other character. An example of unformatted input is
getline(cin, answer1);
which is shorthand for
getline(cin, answer1, '\n'); // that is to say, the delimiter
// has a default value of '\n'
(just to make it clear that the newline character '\n' has a special meaning in this case). getline, used this way, will read from the stream until it encounters a newline.
And therein lies your problem. After the previous, formatted input function, there is stuff left in the stream that you don't care about. It is probably just a newline (although if the user provided 123abc, it will be abc\n), in which case getline will give you an empty string -- there's an empty line in the stream, so what else can it do?
There are several ways to deal with this condition. One is to say
#include <iostream>
#include <limits>
cin.ignore(numeric_limits<streamsize>::max(), '\n');
This is essentially saying: ignore everything up to the next newline (the numeric_limits<streamsize>::max() is a very large number that cin.ignore treats as infinity). Another is
cin >> ws;
which says: "ignore everything up to the next non-whitespace character", although this will ignore leading spaces in the next line, and it will not ignore abc if the user provided 123abc. In your case, I believe there is no reason to change gears from formatted input -- you don't want a line but first and last names. I suggest using
string fname, lname;
cin >> fname >> lname;
This will also eliminate the other error (that you're using an error code as string index), because you won't have to search for a space in the string that may not be there.
Do
cin >> ans;
cin >> std::ws;
before the while loop. Also, check
v=answer1.find(" ", 0);
for
std::npos
which is the value returned if find was unsuccessful.

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

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');

getline not asking for input? [duplicate]

This question already has answers here:
Need help with getline() [duplicate]
(7 answers)
Closed 7 years ago.
This is probably a very simple problem but forgive me as I am new.
Here is my code:
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
int main ()
{
string name;
int i;
string mystr;
float price = 0;
cout << "Hello World!" << endl;
cout << "What is your name? ";
cin >> name;
cout << "Hello " << name << endl;
cout << "How old are you? ";
cin >> i;
cout << "Wow " << i << endl;
cout << "How much is that jacket? ";
getline (cin,mystr);
stringstream(mystr) >> price;
cout << price << endl;
system("pause");
return 0;
}
The problem is that when asked how much is that jacket? getline does not ask the user for input and just inputs the initial value of "0". Why is this?
You have to be careful when mixing operator>> with getline. The problem is, when you use operator>>, the user enters their data, then presses the enter key, which puts a newline character into the input buffer. Since operator>> is whitespace delimited, the newline character is not put into the variable, and it stays in the input buffer. Then, when you call getline, a newline character is the only thing it's looking for. Since that's the first thing in the buffer, it finds what it's looking for right away, and never needs to prompt the user.
Fix:
If you're going to call getline after you use operator>>, call ignore in between, or do something else to get rid of that newline character, perhaps a dummy call to getline.
Another option, and this is along the lines of what Martin was talking about, is to not use operator>> at all, and only use getline, then convert your strings to whatever datatype you need. This has a side effect of making your code more safe and robust. I would first write a function like this:
int getInt(std::istream & is)
{
std::string input;
std::getline(is,input);
// C++11 version
return stoi(input); // throws on failure
// C++98 version
/*
std::istringstream iss(input);
int i;
if (!(iss >> i)) {
// handle error somehow
}
return i;
*/
}
You can create a similar function for floats, doubles and other things. Then when you need in int, instead of this:
cin >> i;
You do this:
i = getInt(cin);
Its because you have a '\n' left lying on the input stream from a previous call.
cin >> i; // This reads the number but the '\n' you hit after the number
// is still on the input.
The easiest way to do interactive user input is to make sure each line is processed independently (as the user will hit enter after each prompt).
As a result always read a line, then process the line (until you get familiar with the streams).
std::string line;
std::getline(std::cin, line);
std::stringstream linestream(line);
// Now processes linestream.
std::string garbage;
lienstream >> i >> garbage; // You may want to check for garbage after the number.
if (!garbage.empty())
{
std::cout << "Error\n";
}
Ignore some characters until line feed is reached.
cin.ignore(256, '\n')
getline (cin,mystr);

Why getline skips first line?

In the following code, getline() skips reading the first line.
I noted that when commenting the "cin >> T" line, it works normally. But I can't figure out the reason.
I want to read an integer before reading lines! How to fix that?
#include <iostream>
using namespace std;
int main () {
int T, i = 1;
string line;
cin >> T;
while (i <= T) {
getline(cin, line);
cout << i << ": " << line << endl;
i++;
}
return 0;
}
cin >> T;
This consumes the integer you provide on stdin.
The first time you call:
getline(cin, line)
...you consume the newline after your integer.
You can get cin to ignore the newline by adding the following line after cin >> T;:
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
(You'll need #include <limits> for std::numeric_limits)
Most likely there is a newline in your input file, and that is being processed immediately, as explained on this page:
http://augustcouncil.com/~tgibson/tutorial/iotips.html
You may want to call cin.ignore() to have it reject one character, but, you may want to read more of the tips, as there are suggestions about how to handle reading in numbers.
This line only reads a number:
cin >> T;
If you want to parse user input you need to take into account they keep hitting <enter> because the input is buffered. To get around this somtimes it is simpler to read interactive input using getline. Then parse the content of the line.
std::string userInput;
std::getline(std::cin, userInput);
std::stringstream(userInput) >> T;