String length getting reduced by using getline? - c++

I am using getline and ignore but something is not working properly,
Below is the sample code which am not able to understand how it is working.
int main()
{
string str;
int t,length;
cin>>t; // t is the number of test cases
while(t--!=0)
{
cin.ignore();
getline(cin,str);
length=str.size();
cout<<"length="<<length;
}
}
Sample output:
2
hey hi
length 6
hey hi
length 5
Why is the length decreasing? Is this because of getline and ignore function? Any help would be appreciated.

The reason it is giving a different length is becaus your ignore() function ignores only one character. The first time round it ignores the return key you pressed after entering the number. But std::getline() deletes the return character for you. So the second time round ignore() deletes the first letter of your string making it "eh hi".
int main()
{
string str;
int t, length;
cin >> t; // does not remove the RETURN character
while(t-- != 0)
{
// first removed RETURN character after removes first letter
cin.ignore();
getline(cin, str);
length = str.size();
cout << "length = " << length;
}
}
Try using this instead:
int main()
{
string str;
int t, length;
cin >> t; // does not remove the RETURN character
while(t-- != 0)
{
// cin.ignore(); // dont do this here please
// cin >> ws skips all whitespace characters
// including the return character
getline(cin >> ws, str);
length = str.size();
cout << " length = " << length;
}
}
Alternatively (maybe better) you can move the ignore() function out of the loop to where t is really needed:
#include <limits>
int main()
{
string str;
int t, length;
cin >> t; // does not remove the RETURN character
// ignore as many characters as necessary including the return
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
while(t-- != 0)
{
// cin.ignore(); // not here
getline(cin, str);
length = str.size();
cout << " length = " << length;
}
}
The cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n'); looks complicated but it is the only way to guarantee that any spurious characters (like spaces) are removed. You can probably get away with just cin.ignore() for the exercise if you want.
Read up on std::istream::ignore()

cin.ignore() defaults to ignoring one character.
If you output your string each time, you'll see that in later cases the string is equal to "ey hi". The h is being dropped.
The value of the string held by cin drops its first character before being passed to getline.
Since you're using getline, you can simply remove the cin.ignore() from your loop and your program should work as intended.
However, you should also change your cin>>t; line. In this case, the ignore() is dropping the line return after the input value 2. A stringstream here allows for a getline(...) function, or alternatively you can use cin.ignore(str.max_size(), '\n');.
In the case of the stringstream, your code would become:
#include <sstream> // stringstream
#include <string> // std::string
#include <iostream> // cin
int main()
{
string str;
int t,length;
getline(cin, str);
std::stringstream stream;
stream << str;
if (!(stream >> t)) {
// Couldn't process to int
}
// cin>>t; // t is the number of test cases
// No longer need this line.
while(t--!=0)
{
// cin.ignore(); Drop this too
getline(cin,str);
length=str.size();
cout<<"length="<<length;
}
}

If you are not interested in whitespace,
then use getline(cin >> ws, str)

Related

How to get string input n times? [duplicate]

This question already has answers here:
Why does std::getline() skip input after a formatted extraction?
(5 answers)
Closed 3 years ago.
I have a C++ program. I want to get a number from the user (t) and force the user to enter line t times but the program's execution terminates after 1 iteration. This is the code:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
int t;
cin >> t;
for (int i=0; i< t; i++) {
getline(cin, str);
cout << str;
}
return 0;
}
Can anyone explain me why this happening and how to solve it?
Thank you my friends.
The newline character is still in the buffer when you do cin >> t so the next line you read will be blank. When you mix formatted input (>>) and unformatted (std::getline) you often get in situations like this and you need to take measures when switching to unformatted input. Example remedy:
#include <iostream>
#include <limits>
#include <string>
using namespace std;
int main() {
string str;
int t;
cin >> t;
cin.ignore(numeric_limits<streamsize>::max(), '\n'); // skip the rest of the line
for(int i = 0; i < t; i++) {
if(getline(cin, str)) // check that the getline actually succeeded
cout << str << '\n';
else
break;
}
return 0;
}
When you enter your first character (the times to repeat), a character is left in the cin buffer - newlines are not consumed by cin >>. As a result, getline(cin, str) reads this character and takes it as the first input, which then empties the buffer out and lets you enter the others.
You can clear the buffer with std::cin.ignore(1); to remove that trailing character - this lets your code run as anticipated. Why not just use cin >> str, though? That solves the problem and avoids a call to getline.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
int t;
cin >> t;
//clear one character out of buffer
cin.ignore(1);
//note that 1 is used for demonstration purposes
//in development code, INT_MAX, numeric_limits<streamsize>::max(),
//or some other large number would be best, followed
//by std::cin.clear()
for (int i=0; i< t; i++) {
cout << "input: ";
//you could use cin >> str; instead of getline(cin, str);
getline(cin, str);
cout << "got: " << str << std::endl;
}
return 0;
}
Demo

C++ - Sanitize Integer Whole Number Input

I currently am using a function I found in another StackOverflow post(I can't find it), that I am using before, named "GetInt". My issue with it is that if the user inputs something like "2 2 2" it puts it into my next two Cin's. I have tried getLine, but it requires a string and I am looking for an int value. How would I structure a check to sanitize for an integer value greater than 2 and throw an error to the 2 2 2 answer.
#include <iostream>
#include <string>
#include <sstream>
#include "Board.cpp"
#include "Player.cpp"
using namespace std;
int getInt()
{
int x = 0;
while (!( cin >> x))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Please input a proper 'whole' number: " << endl;
}
return (x);
}
and my call
do
{
//do
//{
cout << "How many players are there? \n";
numberOfPlayers = getInt();
//} while (isdigit(numberOfPlayers) == false);
} while (numberOfPlayers < 2);
EDIT:
I chose Justin's answer because it was the closest to my original code and solved the issue without major changes.
Integers are delimited by spaces and the input 2 2 2 is just multiple integers. If you want to make sure that just one integer is entered per line you could skip whitespace characters until a newline is found. If a non-whitespace is found prior to a newline you could issue an error:
numberOfPlayers = getInt();
int c;
while (std::isspace(c = std::cin.peek()) && c != '\n') {
std::cin.ignore();
}
if (c != std::char_traits<char>::eof() && c != '\n') {
// deal with additional input on the same line here
}
You were on the right track with std::getline. You read the whole line as a string, then put it into a std::istringstream and read the integer out.
std::string line;
if( std::getline(cin, line) ) {
std::istringstream iss(line);
int x;
if( iss >> x ) return x;
}
// Error
This will have the effect of discarding any fluff that comes after the integer. It will only error if there is no input or no integer could be read.
If you want to have an error when stuff appears after the integer, you could take advantage of the way strings are read from a stream. Any whitespace is okay, but anything else is an error:
std::istringstream iss(line);
int x;
if( iss >> x ) {
std::string fluff;
if( iss >> fluff ) {
// Error
} else {
return x;
}
}
Change your code to this:
int getInt()
{
int x = 0;
while (!( cin >> x))
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Please input a proper 'whole' number: " << endl;
}
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
return (x);
}
Your code to ignore the rest of the line after receiving the integer is only called if the integer collection fails (for example, you type "h" as the number of players).

How to read in user entered comma separated integers?

I'm writing a program that prompts the user for:
Size of array
Values to be put into the array
First part is fine, I create a dynamically allocated array (required) and make it the size the user wants.
I'm stuck on the next part. The user is expected to enter in a series of ints separated by commas such as: 1,2,3,4,5
How do I take in those ints and put them into my dynamically allocated array? I read that by default cin takes in integers separated by whitespace, can I change this to commas?
Please explain in the simplest manner possible, I am a beginner to programming (sorry!)
EDIT: TY so much for all the answers. Problem is we haven't covered vectors...is there a method only using the dynamically allocated array I have?
so far my function looks like this. I made a default array in main. I plan to pass it to this function, make the new array, fill it, and update the pointer to point to the new array.
int *fill (int *&array, int *limit) {
cout << "What is the desired array size?: ";
while ( !(cin >> *limit) || *limit < 0 ) {
cout << " Invalid entry. Please enter a positive integer: ";
cin.clear();
cin.ignore (1000, 10);
}
int *newarr;
newarr = new int[*limit]
//I'm stuck here
}
All of the existing answers are excellent, but all are specific to your particular task. Ergo, I wrote a general touch of code that allows input of comma separated values in a standard way:
template<class T, char sep=','>
struct comma_sep { //type used for temporary input
T t; //where data is temporarily read to
operator const T&() const {return t;} //acts like an int in most cases
};
template<class T, char sep>
std::istream& operator>>(std::istream& in, comma_sep<T,sep>& t)
{
if (!(in >> t.t)) //if we failed to read the int
return in; //return failure state
if (in.peek()==sep) //if next character is a comma
in.ignore(); //extract it from the stream and we're done
else //if the next character is anything else
in.clear(); //clear the EOF state, read was successful
return in; //return
}
Sample usage http://coliru.stacked-crooked.com/a/a345232cd5381bd2:
typedef std::istream_iterator<comma_sep<int>> istrit; //iterators from the stream
std::vector<int> vec{istrit(in), istrit()}; //construct the vector from two iterators
Since you're a beginner, this code might be too much for you now, but I figured I'd post this for completeness.
A priori, you should want to check that the comma is there, and
declare an error if it's not. For this reason, I'd handle the
first number separately:
std::vector<int> dest;
int value;
std::cin >> value;
if ( std::cin ) {
dest.push_back( value );
char separator;
while ( std::cin >> separator >> value && separator == ',' ) {
dest.push_back( value );
}
}
if ( !std::cin.eof() ) {
std::cerr << "format error in input" << std::endl;
}
Note that you don't have to ask for the size first. The array
(std::vector) will automatically extend itself as much as
needed, provided the memory is available.
Finally: in a real life example, you'd probably want to read
line by line, in order to output a line number in case of
a format error, and to recover from such an error and continue.
This is a bit more complicated, especially if you want to be
able to accept the separator before or after the newline
character.
You can use getline() method as below:
#include <vector>
#include <string>
#include <sstream>
int main()
{
std::string input_str;
std::vector<int> vect;
std::getline( std::cin, input_str );
std::stringstream ss(str);
int i;
while (ss >> i)
{
vect.push_back(i);
if (ss.peek() == ',')
ss.ignore();
}
}
The code is taken and processed from this answer.
Victor's answer works but does more than is necessary. You can just directly call ignore() on cin to skip the commas in the input stream.
What this code does is read in an integer for the size of the input array, reserve space in a vector of ints for that number of elements, then loop up to the number of elements specified alternately reading an integer from standard input and skipping separating commas (the call to cin.ignore()). Once it has read the requested number of elements, it prints them out and exits.
#include <iostream>
#include <iterator>
#include <limits>
#include <vector>
using namespace std;
int main() {
vector<int> vals;
int i;
cin >> i;
vals.reserve(i);
for (size_t j = 0; j != vals.capacity(); ++j) {
cin >> i;
vals.push_back(i);
cin.ignore(numeric_limits<streamsize>::max(), ',');
}
copy(begin(vals), end(vals), ostream_iterator<int>(cout, ", "));
cout << endl;
}
#include <iostream>
using namespace std;
int main() {
int x,i=0;
char y; //to store commas
int arr[50];
while(!cin.eof()){
cin>>x>>y;
arr[i]=x;
i++;
}
for(int j=0;j<i;j++)
cout<<arr[j]; //array contains only the integer part
return 0;
}
The code can be simplified a bit with new std::stoi function in C+11. It takes care of spaces in the input when converting and throws an exception only when a particular token has started with non-numeric character. This code will thus accept input
" 12de, 32, 34 45, 45 , 23xp,"
easily but reject
" de12, 32, 34 45, 45 , 23xp,"
One problem is still there as you can see that in first case it will display " 12, 32, 34, 45, 23, " at the end where it has truncated "34 45" to 34. A special case may be added to handle this as error or ignore white space in the middle of token.
wchar_t in;
std::wstring seq;
std::vector<int> input;
std::wcout << L"Enter values : ";
while (std::wcin >> std::noskipws >> in)
{
if (L'\n' == in || (L',' == in))
{
if (!seq.empty()){
try{
input.push_back(std::stoi(seq));
}catch (std::exception e){
std::wcout << L"Bad input" << std::endl;
}
seq.clear();
}
if (L'\n' == in) break;
else continue;
}
seq.push_back(in);
}
std::wcout << L"Values entered : ";
std::copy(begin(input), end(input), std::ostream_iterator<int, wchar_t>(std::wcout, L", "));
std::cout << std::endl;
#include<bits/stdc++.h>
using namespace std;
int a[1000];
int main(){
string s;
cin>>s;
int i=0;
istringstream d(s);
string b;
while(getline(d,b,',')){
a[i]= stoi(b);
i++;
}
for(int j=0;j<i;j++){
cout<<a[j]<<" ";
}
}
This code works nicely for C++ 11 onwards, its simple and i have used stringstreams and the getline and stoi functions
You can use scanf instead of cin and put comma beside data type symbol
#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[10],sum=0;
cout<<"enter five numbers";
for(int i=0;i<3;i++){
scanf("%d,",&a[i]);
sum=sum+a[i];
}
cout<<sum;
}
First, take the input as a string, then parse the string and store it in a vector, you will get your integers.
vector<int> v;
string str;
cin >> str;
stringstream ss(str);
for(int i;ss>>i;){
v.push_back(i);
if(ss.peek() == ','){
ss.ignore();
}
}
for(auto &i:v){
cout << i << " ";
}

Transformation to lower case in C++

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include <string>
#include <algorithm>
using namespace std;
string A,B;
int main()
{
int t,l,i;
scanf("%d",&t);
while(t--)
{
std::string str;
std::getline(cin, str);
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
cout<<str;
/*for(i=0;i<s.length();i++)
{
s[i]=toupper(s[i]);
}*/
}
return 0;
}
i wrote this code to convert to lower case but when run on ideone with input
1
hola please!!!
it shows output no can u tell or correct it morever this will help me learn the use of std:lowercase function taking getline cin as input rather than considering it as array
The problem is definitely with the way you are reading in. scanf("%d",&t); doesn't consume the return character, so it is still there on the getline, which will get an empty sting. Change it to scanf("%d\r",&t).
If you simplify the code, the problem can be reduced to:
int main() {
int t;
scanf("%d",&t);
std::string str;
std::getline(cin, str);
std::cout<<str;
}
This is because scanf reads from the input until it reaches a character that doesn't match, and it leaves that character in the input buffer. You input is "1\nhola please!\n\0", so scanf reads the 1, and leaves the rest: "\nhola please!\n\0". Then, you tell it to read until the next \n is found, which is immediately, so it returns an empty string.
The solution is: after using std::cin >> or scanf or whatever, if the next thing you want to do is read the rest of the line, you want to ignore that leading newline character. The C++ way to do this is std::cin.ignore(0xFFFFFFFF,'\n');, which will ignore the rest of the line. Alternatively, use scanf("%d\n" &t); to get the scanf to read in the newline character.
Related, you never check the validity of any of your input:
int main() {
int num_lines=0; //variables on different lines and initialized
std::cin >> num_lines
if (!std::cin)
return 1;
std::string str;
for(int j=0; j<num_lines && std::getline(sd::cin, str); ++j) {
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
std::cout << str;
}
return 0;
}
Or simply use < boost/algorithm/string.hpp > header and function boost::to_lower().
int t = 0;
scanf("%d",&t);
std::cin.ignore();
while(t--) {
std::string str;
std::getline(cin, str);
boost::to_lower(str);
std::cout << str << std::endl;
}

c++ unable to get proper string input

I am new to programming just wrote this simple function to calculate length of a string but I am unable to take input string from the user properly(have tried my alternatives).
/////////Function to calculate length of a string////////////////////
void str_length(){
char str[30];
int counter=0;
cout << "Enter string: ";
gets(str);
//cin.getline(str,256);
//cin >> str;
for(int i=0;str[i] != '\0';i++){
counter++;
}
cout << "String length is: " << counter << endl;
}
///////////////////////////////////////////////////////////////
of all possible ways the program either exits abruptly or with 'cin' I can only get partial string till the first space.
If you tried cin.getline(str,256), you'd have needed your buffer to be declared as char str[256].
You shouldn't really be involving yourself with these things however. Stick with std::string:
std::string str; // Declare a string
std::getline(std::cin, str); // Get a line from the std::cin stream and put it in str
unsigned int stringLength = str.length(); // get the length of the string
Why not use the std::string library. It is nice and easy to use.
void str_length()
{
std::string line;
std::cout << " Please input current line: " << std::endl;
std::getline(std::cin, line);
std::cout << "the length of input string is: " << line.length() <<std::endl;
}
I can only agree with my previous speakers and would recommend you to use the better variant by using std::string. Nevertheless if you really want to use C-String than you can use this approach:
std::cin.get(char *s, streamsize n)
This method reads in characters until you press the enter button.
#include<iostream>
#define SIZE 40;
using namespace std;
int main() {
char str[SIZE];
cin.get(str, SIZE-1);
cout << str << endl;
return 0;
}
You should be aware if you have once created an buffer overflow that you will get some trouble at the next call of this method. The problem is that your input buffer will save the remaining characters and at the next call your methods will only read in the remaining characters. To solve this problem you have to clear your input buffer before each input.
Best practice is to use this code in front of each cin.get()
while(cin.get() != '\n');
#include <iostream>
void str_length(){
char str[30];
std::cout<< "Enter string: ";
std::cin>>str;
int counter=0;
for(counter=0;str[counter] != '\0';counter++){}
std::cout<<"String length is "<<counter<<std::endl;
}
OR
#include <iostream>
#include <string>
void str_length(){
std::string str;
std::cout<<"Enter string: "<<std::endl;
std::cin>>str;
std::cout<<"String length is "<<str.size()<<endl;
}