C++ using cin.ignore() to remove first non-int from the input stream [closed] - c++

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
So For example if I input:
33a
and I want to remove "a" from the stream and store 33 into an int, how to do this using cin.ignore?
Edits:
To be more precise:so If I have input:
2
3
4a
b
or
2
3
4
a
b
I want to store those 2,3,4 into an array, and also when encountered 'a'(first non-int char), ignore 'a', and then jumped out the input reading loop(ie
while(cin>>num)
)?

TL;DR version based on question edit:
The smart way is to use a std::vector to store the read values and ignore all the messiness of an array of unknown size.
Then
while not done
read a value
if value successfully read
store value
ignore to the end of the line
else
clear stream error
ignore to the end of the line
I'm only providing a pseudocode answer because this looks too much like a homework assignment at this point. All of the required bits and pieces are discussed below and it's up to OP to assemble them correctly.
If you MUST use an array, before storing a value test to make sure you will not overrun the end of the array by storing the value.
Old answer:
Link to documentation.
cin.ignore() ignores one character.
cin.ignore(10) ignores up to 10 characters.
cin.ignore(10, ' ') ignores up to 10 characters or it finds and consumes a space.
Another common case is discarding the rest of the line: cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n')
So...
int val;
cin >>val;
cin.ignore();
will handle the simple case of reading an int and discarding the next character. Input of "33a" will result in 33 being stored in val, 'a' being ignored, and the end of line (enter keypress) used to trigger this chain of events is left in cin for future consumption. This could be a problem so,
int val;
cin >>val;
cin.ignore((std::numeric_limits<std::streamsize>::max(), '\n');
will read 33 into val, discard 'a` and anything else the user typed in. This may not be what you want. For example, input of "33a 44b"
int val;
cin >>val;
cin.ignore((std::numeric_limits<std::streamsize>::max(), ' ');
will read 33 into val, discard 'a' and anything else the user typed in up to the first space. Another pass through the above code will result in 44 in val, the discard of 'b', and the end of line staying in cin.
Attempting to use std::getline at this point is bad. It will instantly consume the end of line and return an empty string. However, a third pass though the above code will discard the end of line as whitespace and wait for more input from the user.
However users are lousy sources of input, so you want to protect cin >>val; from a user typing in something like "blah", hitting enter, and trying again. "blah cannot convert to an int, so cin will be set into the error state and you need to acknowledge this before continuing.
int val;
while (!(cin >>val)) // continue as long as the user has finger trouble
{
cin.clear() // clear the error state
// discard the rest of the line because who knows what other garbage is on it.
cin.ignore((std::numeric_limits<std::streamsize>::max(), '\n');
// probably want to notify the user and prompt for good input here.
}
//whichever ignore code fits your usecase
or similar will handle the bad input case.

Although it's not immediately obvious now to do it, streams actually incorporate a way to deal with this quite directly (at least assuming I've understood the question correctly).
When you read (for example) a number from a stream, the stream skips any white-space before the number. To figure out whether a character is white-space or not, the stream uses an associated locale--specifically, the locale's ctype facet.
To have the stream ignore everything except digits, we can provide a locale that classifies everything except digits as white space.
#include <locale>
#include <iostream>
#include <algorithm>
#include <vector>
#include <sstream>
#include <iterator>
class my_ctype : public std::ctype<char> {
public:
mask const *get_table() {
static std::vector<std::ctype<char>::mask>
table(table_size, (mask)space);
std::fill_n(table.begin() + '0', 10, (mask)digit);
return &table[0];
}
my_ctype(size_t refs=0) : std::ctype<char>(get_table(), false, refs) { }
};
int main() {
std::istringstream s("1 2, 9 3 a 4b 2 5");
s.imbue(std::locale(std::locale(), new my_ctype));
int i;
while (s >> i)
std::cout << i << "\n";
}
Result:
1
2
9
3
4
2
5
Note that with this, we don't have to use ignore (or anything else, except the normal stream extractor) to ignore the garbage we don't care about in the stream. The other side of this is that this is useful (at least primarily) when assigned to the stream as a whole. If you want to read 4 numbers this way, then be able to go back to reading everything normally, this probably won't be a useful technique for your situation.

Related

String.length() shows incorrect value [duplicate]

This question already has answers here:
Read whole ASCII file into C++ std::string [duplicate]
(9 answers)
Closed 3 years ago.
I am trying this following code in cpp
#include <iostream>
#include <string>
void Strlength(const string& s) {
cout << s.length() << endl;
}
int main() {
string s;
cin >> s;
cout << s.length() << endl;
Strlength(s);
return 0;
}
The string which I am giving as input is 100,000 characters long and is like "xxxxxxx...xxxxabcde"(fill the ... with remaining x)
This gives me the output as
4095
4095
I am expecting the output to be 100000. what am I doing wrong?
This relates to one of the hackerrank problem (Test case 10): String Similarity
Assuming you describe the input correctly, that is it is one single "word", then the issue is not in your code. The issue must be in the environment which runs the code. It has some kind of mechanism to feed the standard input to your program. Either that has a limitation on total input length, or it has a limitation of line length. 4 kilobytes is 4096 bytes, so perhaps your input is limited by that: 4095 chars of the word plus a newline character (or terminating 0 byte of string, or whatever).
If you are running this under some kind of web interface in browser, the problem could even be, that the input field in the web page has that limitation.
If you need to dig into this, try to read char by char and see what you get, how many chars and how many newlines. Also examine cin.fail(), cin.eof(), cin.bad() and cin.good(). For the question code, you should expect failbit to be false, and eofbit might be true oe false depending on how the input was truncated.

How exactly does the extract>> operator works in C++

I am a computer science student, an so do not have much experience with the C++ language (considering it is my first semester using this language,) or coding for that matter.
I was given an assignment to read integers from a text file in the simple form of:
19 3 -2 9 14 4
5 -9 -10 3
.
.
.
This sent me of on a journey to understand I/O operators better, since I am required to do certain things with this stream (duh.)
I was looking everywhere and could not find a simple explanation as to how does the extract>> operator works internally. Let me clarify my question:
I know that the extractor>> operator would extract one continues element until it hits space, tab, or newline. What I try to figure out is, where would the pointer(?) or read-location(?) be AFTER it extracts an element. Will it be on the last char of the element just removed or was it removed and therefore gone? will it be on the space/tab/'\n' character itself? Perhaps the beginning of the next element to extract?
I hope I was clear enough. I lack all the appropriate jargon to describe my problem clearer.
Here is why I need to know this: (in case anyone is wondering...)
One of the requirements is to sum all integers in each line separately.
I have created a loop to extract all integers one-by-one until it reaches the end of the file. However, I soon learned that the extract>> operator ignores space/tab/newline. What I want to try is to extract>> an element, and then use inputFile.get() to get the space/tab/newline. Then, if it's a newline, do what I gotta do.
This will only work if the stream pointer will be in a good position to extract the space/tab/newline after the last extraction>>.
In my previous question, I tried to solve it using getline() and an sstring.
SOLUTION:
For the sake of answering my specific question, of how operator>> works, I had to accept Ben Voigt's answer as the best one.
I have used the other solutions suggested here (using an sstring for each line) and they did work! (you can see it in my previous question's link) However, I implemented another solution using Ben's answer and it also worked:
.
.
.
if(readFile.is_open()) {
while (readFile >> newInput) {
char isNewLine = readFile.get(); //get() the next char after extraction
if(isNewLine == '\n') //This is just a test!
cout << isNewLine; //If it's a newline, feed a newline.
else
cout << "X" << isNewLine; //Else, show X & feed a space or tab
lineSum += newInput;
allSum += newInput;
intCounter++;
minInt = min(minInt, newInput);
maxInt = max(maxInt, newInput);
if(isNewLine == '\n') {
lineCounter++;
statFile << "The sum of line " << lineCounter
<< " is: " << lineSum << endl;
lineSum = 0;
}
}
.
.
.
With no regards to my numerical values, the form is correct! Both spaces and '\n's were catched:
Thank you Ben Voigt :)
Nonetheless, this solution is very format dependent and is very fragile. If any of the lines has anything else before '\n' (like space or tab), the code will miss the newline char. Therefore, the other solution, using getline() and sstrings, is much more reliable.
After extraction, the stream pointer will be placed on the whitespace that caused extraction to terminate (or other illegal character, in which case the failbit will also be set).
This doesn't really matter though, since you aren't responsible for skipping over that whitespace. The next extraction will ignore whitespaces until it finds valid data.
In summary:
leading whitespace is ignored
trailing whitespace is left in the stream
There's also the noskipws modifier which can be used to change the default behavior.
The operator>> leaves the current position in the file one
character beyond the last character extracted (which may be at
end of file). Which doesn't necessarily help with your problem;
there can be spaces or tabs after the last value in a line. You
could skip forward reading each character and checking whether
it is a white space other than '\n', but a far more idiomatic
way of reading line oriented input is to use std::getline to
read the line, then initialize an std::istringstream to
extract the integers from the line:
std::string line;
while ( std::getline( source, line ) ) {
std::istringstream values( line );
// ...
}
This also ensures that in case of a format error in the line,
the error state of the main input is unaffected, and you can
continue with the next line.
According to cppreference.com the standard operator>> delegates the work to std::num_get::get. This takes an input iterator. One of the properties of an input iterator is that you can dereference it multiple times without advancing it. Thus when a non-numeric character is detected, the iterator will be left pointing to that character.
In general, the behavior of an istream is not set in stone. There exist multiple flags to change how any istream behaves, which you can read about here. In general, you should not really care where the internal pointer is; that's why you are using a stream in the first place. Otherwise you'd just dump the whole file into a string or equivalent and manually inspect it.
Anyway, going back to your problem, a possible approach is to use the getline method provided by istream to extract a string. From the string, you can either manually read it, or convert it into a stringstream and extract tokens from there.
Example:
std::ifstream ifs("myFile");
std::string str;
while ( std::getline(ifs, str) ) {
std::stringstream ss( str );
double sum = 0.0, value;
while ( ss >> value ) sum += value;
// Process sum
}

how to force user to input exactly 8 characters into string

how can I limit a user to input 8 characters into string?
can something like this work?
string MyString;
getline(std::cin, MyString, 8);
or maybe there is a different idea to accomplish it
thanks in advance
clarification:
I want to enable the user to input up to 8 characters in the string, but he may enter less.
You can use a loop..
while (MyString.length() != 8) {
std::cout << "Enter exactly 8 characters:";
getline(std::cin, MyString);
}
its hard to think this will help considering my experience (1mnth!)
at codecademy.com in the "Python" language one might say something like:
my_string = "jackie"
len(my_string)
#would print 5
if my_string is <= ..... # if my string is greater or equal to print the following
print "name is too long "
Hope that generated something other than disgust
sincerely dedicated noobie
There is a difference between requesting 8 characters from the User and preventing the User from entering more than 8.
Requesting 8 from User
You can request 8 characters from the User, but the User is allowed to enter as many characters as the User wants until a newline character is entered. This is the behavior of the standard console input.
The console has buffered the all the characters. Depending on the extraction method, you will be extracting 8 characters from the input buffer into your variable. The remaining characters are still in the buffer.
Preventing User from entering more than 8
This is typically used in entering passwords. The standard C++ input facilities cannot help here.
You will need platform specific control of the input source. You will need to read each character, test for a newline and optionally echo back either the character, a uniform character like '*', or not display any characters.
Since it is platform specific, look up the API for your platform.
#include <iostream>
#include <string>
int main(){
std::string str;
bool cStr = true; //check string
while (cStr){
std::getline(std::cin, str);
if (str.size() <= 8) cStr = false;
}
}
You can add a bool object to test your string using an if-statement. If the string size is less than or equal to 8, it will then advert the bool statement to false allowing the exit of the while loop.

cin.getline(char, int) gets skipped when in a loop

This is the code I have been trying to execute on TurboC++ 3.0 (Yes, I know it's ancient but can't help it), when the program goes into the loop, it skips the value of y every time including the first attempt. Any help would be appreciated but please avoid rubbing salt into wounds by asking why TurboC++ 3.0. Thanks in advance.
void main()
{
int x, z;
char y[10];
for (int i=0;i<5;i++)
{
cout<<"\nX:";
cin >> x;
cout<<"\nY:";
cin.getline(y,10);
cout<<"\nZ:";
cin>>z;
}
for(i=0;i<5;i++)
{
cout<<x<<"\n";
cout.write(y, 10)<<"\n";
cout<<z<<"\n\n";
}
}
and even if I use cin.get(var) where var is a character, i still get weird results like a heart, diamond or even a smiley.
You get weird results because you are not terminating your c style string with a null character.('\0').
The problem you are facing is because , fail bit or eof bit is set. To remove that, do the following:-
You can use
cin.clear() ;
to clear if any error bits are set and then use
cin.ignore(100, '\n') ;
// 100 is just a random no, change it depending on your size of input.
to ignore any irrelevant characters int the stream.
or you can do the following:-
after cin>>x just type cin.ignore(), it will flush out any newline characters present in the buffer .
it skips the value of y
cin >> x reads the input until it finds something that's not a digit - in this case, the end-of-line character. That character is left in the stream.
getline reads the input until it finds an end-of-line character (or the end of the stream). Since you've left one in the stream, it finds it straight away and doesn't read anything.
You can call cin.ignore(-1,'\n') to ignore the remainder of the first line after reading x (assuming your prehistoric library behaves like the modern one).
i still get weird results like a heart, diamond or even a smiley
cout.write(y, 10) is wrong - there are up to 9 valid characters in y, followed by the null terminator. You want cout << y to treat it as a null-terminated string and print only the valid characters.

C++ Infinite Loop

I'm learning C++.
nav is an integer .
I want to ask user for typing a valid value, if he / she type an invalid value.
void main()
{
printf("Type an integer : ");
if(!scanf("%d", &nav))
{
system("cls");
printf("Invalid ! \n");
main();
}
}
But it's blinking after typing first value . It's blinking like reloading screen. I think it's infinite loop.
How can i do it in right way ? I want to ask a number from users, until it's typing a real number .
If the user types an invalid input, scanf() won't consume it, and you'll be left peeking the same offending input character forever. You need to first read whatever the user enters — I recommend using std::getline() — and then try to parse that with strtol(), sscanf() or std::istringstream. Don't use atoi() because it doesn't report failures.
int nav;
{
string line;
while (getline(cin, line))
if (istringstream(line) >> nav)
break;
}
EDIT: See the comments for a rather beautiful rendition of the above logic. I've left it out of the answer because: a) I don't want to steal someone else's idea, and b) I'm not sure I'd present a newcomer to C++ with that formulation — not in one go, at least.
P.S.: You can't call main() in C++.
Two things.
Scanf needs the 'enter' key pressed before it will process input, so the blinking could just be the cursor waiting for the next key.
Also, calling main from main is fairly non-standard. You should look into a 'while' loop.
Your program is not a good one, but nevertheless I will tell you what is happening.
In C/C++, when scanf cannot read an integer (%d) from input, it wouldn't read anything. That is, whatever prevented scanf from reading an int, will remain there. On the next scanf the same character is going to cause an error.
Let me demonstrate by an example. Imagine you are reading many integers from this input:
12 13 Shahbaz 15
Now if you call scanf with %d, you will read 12 and the input would be:
13 Shahbaz 15
Next, you call scanf with %d and you will read 13. now the input would be:
Shahbaz 15
Again, you call scanf with %d. Here, the input begins with an S (after the whitespace) which makes scanf return with a failure as it could not read an integer. The input is left untouched (save perhaps for the whitespace). That is, the input will be:
Shahbaz 15
As you can see, reading the input with %d will give you the exact same error and you are stuck in an infinite loop.
To solve this, you have many choices. This very much depends on how you want to handle the situation, but two methods would be to either read a character (with %c) or a string (with %s) right after printing printf("Invalid\n").
The first method is good for handling input like this:
12 13 q14 15
where q is a mistake that needs to be ignored. The second method is good for handling input like this:
12 13 Shahbaz 15
where the invalid data are meaningful words, but you just want to ignore them.
And the way I would write it, if I wanted to use scanf would be:
int main() // always write int main
{
int nav;
printf("Type an integer: ");
while (scanf("%d", &nav) != 1) // scanf returns number of successful %'s read
{
printf("Invalid number. Try again: ");
scanf("%*s"); // read a %s but ignore it
}
// The rest of the program, using nav
return 0;
}