why i need clear stringstream before reuse? - c++

For example:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main() {
int num = 10;
string str;
stringstream toString;
toString << num;
toString >> str;
cout << str << "\n"; //10
int num2 = 20;
string str2;
toString << num2;
toString >> str2;
cout << str2 << "\n"; //str2 is empty
return 0;
}
I know that I must clear this like:
toString.str("");
toString.clear();
But why doesn't it clear automatically after using operator >>?

If I do toString >> a >> b >> c and the first one fails, I don't want the flag to be cleared so that the final state appears to have succeeded.

After the first read toString >> str;. then the rdstate() of toString is std::ios_base::eofbit, because during the reading of str the end of the string has been reached.
Then the line toString << num2; does not modify the string stored in toString but sets the failbit of toString. That is the standard behavior of all formatted output.
The line toString >> str2; does nothing: the failbit is already set, and no reading is performed: str2 stays empty.
The clear() function resets the rdstate() of toString to std::ios_base::goodbit.
The reasons why the >> must not call clear() are:
in case there is an error, then one must be able to test it using the functions bad(), fail(), eof() (or rdstate() directly),
and one can use the operator >> several times:
#include <iostream>
#include <sstream>
int main() {
std::stringstream sstr("10 20");
int i, j;
sstr >> i >> j;
if(!sstr.fail()) {
std::cout << i << " " << j << "\n";
return 0;
}
return 1;
}

Related

How would I split up user input into a char and an integer?

I am working on a project where I have to parse data from user input.
#include <iostream> // for cin and cout
#include <iomanip> // for setw()
#include <cctype> // for toupper()
using namespace std;
int main(){
string playerInput;
cin >> playerInput;
//Player would input strings like C13,C 6, I1, Z 16, etc...
}
return 0;
I've tried something like this, which kinda works but only if the letter proceeds the number in the string.
int myNr = std::stoi(playerInput);
What my end goal is to grab the letter and number from the string, and place them in a char variable and a integer variable respectively. I am stuck on how to proceed from here and could use some help, thanks!
This is the simplest and the shortest way to achieve that (it also ignores spaces and tabs):
int main() {
char ch;
int n;
cin >> ch >> n;
cout << "ch = " << ch << ", n = " << n << endl;
}
I think that other answers are a bit overcomplicated.
You could do like what you had:
char letter = playerInput.front();
playerInput.erase(0);
int number = std::stoi(playerInput);
Of course, that doesn't allow for spaces. Removing spaces can be quite tedious, but it could be done like:
playerInput.erase(
std::remove_if(
begin(playerInput), end(playerInput),
[](uint8_t ch) { return std::isspace(ch); }),
end(playerInput));
Full Demo
Live On Coliru
#include <cctype> // for toupper()
#include <iomanip> // for setw()
#include <iostream> // for cin and cout
#include <algorithm> // for remove_if
static bool ignorable(uint8_t ch) {
return std::isspace(ch)
|| std::ispunct(ch);
}
int main() {
std::string playerInput;
while (getline(std::cin, playerInput)) {
playerInput.erase(
std::remove_if(
begin(playerInput), end(playerInput),
ignorable),
end(playerInput));
if (playerInput.empty())
continue;
char letter = playerInput.front();
playerInput.erase(begin(playerInput));
int number = std::stoi(playerInput);
std::cout << "Got: " << letter << " with " << number << "\n";
}
}
Prints
Got: C with 13
Got: C with 6
Got: I with 1
Got: Z with 16
You have the right idea in using std::stoi. My code expands your approach:
string playerInput;
getline(cin, playerInput);
char c1 = playerInput[0];
int num = stoi(playerInput.substr(1));
The above code receives an input string, then takes out the first character and uses std::stoi on the rest of the string.
Note that I use std::getline to account for the possibility of there being spaces in the input. If you are doing this repeatedly, you will need to add cin.ignore() after each getline() statement. See this link for more info.
std::cin stops reading input when it encounters a space. You can use std::getline() if your input has spaces. To parse your string, you should check out std::stringstream. It allows you to read from a string as if it were a stream like std::cin.
#include <iostream> // for cin and cout
#include <iomanip> // for setw()
#include <cctype> // for toupper()
#include <sstream>
int main(){
std::string playerInput;
int i;
char c;
std::getline(std::cin, playerInput); // Remove trailing newline
std::getline(std::cin, playerInput);
//Player would input strings like C13,C 6, I1, Z 16, etc...
//String Stream
std::stringstream playerInputStream(playerInput);
//Read as if you were reading through cin
playerInputStream >> c; //
playerInputStream >> i;
}
return 0;

C++ "noskipws" is not working as expected, How to properly allow whitespace in string?

I want to be able to type in a full string, including white spaces, and then print that string.
Why is this code not behaving as I would expect?
Code
#include <iostream>
#include <string>
using namespace std;
int main()
{
cout << "Enter your name:\n";
string name;
cin >> noskipws >> name;
cout << "Hello, " << name << "!";
return 0;
}
Output
Enter your name:
>tes test test
Hello, tes!
noskipws stops the stream from skipping leading whitespace before it reads a value. operator>> will still stop reading when it reaches whitespace after a word.
If you want to read a whole line from the console, use std::getline() instead of operator>>:
#include <iostream>
#include <string>
int main()
{
std::cout << "Enter your name:\n";
std::string name;
std::getline(std::cin, name);
std::cout << "Hello, " << name << "!";
return 0;
}
You can define a helper class to give yourself something that looks like an manipulator, if that is the syntax you want to use.
struct Getline {
std::string &s_;
Getline(std::string &s) : s_(s) {}
friend auto & operator >> (std::istream &&is, Getline &&g) {
return std::getline(is, g.s_);
}
};
And then you can use it like this:
int main()
{
std::cout << "Enter your name:\n";
std::string name;
std::cin >> Getline(name);
std::cout << "Hello, " << name << "!";
return 0;
}

Keep getting "member reference base type 'string [1000]' is not a structure or union" error and dont know how to fix it?

This program reads an SSN from the user and checks if it matches an SSN in a text file provided. Tried switching the array to a vector and it didnt work. Tried putting the array in the structure function and using info:: but nothing seems to work. I know this is pretty basic but I cant get it, thanks.
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char* argv[]){
struct info{
string SSN;
string firstName;
string lastName;
};
string list[1000];
string userSSN;
char x;
fstream input(argv[1]);
int i = 0;
while(!input.eof()){
input >> list.x[i] >> list.SSN[i] >> list.firstName[i] >> list.lastName[i];
i++;
}
input.close();
cout << "Input a SSN:" << endl;
cin >> userSSN >> endl;
for(int k = 0; k < i; k++){
if(userSSN.compare(list.SSN[k]) == 0){
cout << "Found at location " << k << endl;
}
}
}
list is just an array of 1000 std::strings. It looks like you need it to be of type info. Even that won't solve your problems as info has no member named x. After that, to access a member of info in an array would be like
list[i].SSN
not
list.SSN[i]
There are so many things wrong with this code that I don't know where to start. Let's see:
Using using namespace std; is almost always a bad idea, and if you have an identifier list, then it's even worse because it conflicts with std::list.
Using std::string without #include <string> is not guaranteed to work. It may work if you include some other standard header, but don't rely on it.
Your variable x is unused.
string list[1000]; should probably be info list[1000];.
list.SSN[i] et al should probably be changed to list[i].SSN.
list.x[i] does not make sense at all and can probably be removed. (Or you meant to read into the otherwise unused x to skip parts of the file.)
You cannot read from std::cin into std::endl. Remove std::endl from that line.
Using std::string's compare function is pretty strange here, just use ==.
The issues in your code were already pointed out in other's answers. I'll show you a "working" example:
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using std::string;
using std::vector;
using std::cout;
using std::cin;
struct info {
char x; // You were reading that from the file so I added it
string SSN;
string firstName;
string lastName;
friend std::istream &operator>>( std::istream &is, info &i ) {
// maybe you should check data input somehow...
is >> i.x >> i.SSN >> i.firstName >> i.lastName;
return is;
}
};
int main(int argc, char* argv[]) {
// check if a file name has been passed as a parameter
string file_name;
if ( argc < 2 ) {
cout << "Please, enter the input file name:\n";
cin >> file_name;
}
else
file_name = argv[1];
std::ifstream input(file_name);
if ( !input ) {
std::cerr << "Error. Unable to open file: " << file_name << '\n';
exit(-1);
}
// Just use a vector to store all the structs
vector<info> my_list;
info temp_info;
while( input >> temp_info ) {
my_list.push_back(temp_info);
}
input.close();
cout << "Input a SSN: ";
string userSSN;
cin >> userSSN;
// That's not cheap. You may want to change the container or sort it
for ( int k = 0; k < my_list.size(); k++ ) {
if ( userSSN == my_list[k].SSN ) {
cout << "Found at location " << k << '\n';
}
}
return 0;
}

C++ - can't move istringstream definition out of loop

I have the following piece of code:
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
string inp, s;
istringstream iss;
do
{
getline (cin, inp);
iss(inp);
int a = 0, b = 0; float c = 0;
iss >> s >> a >> b >> c;
cout << s << " " << a << " " << b << " " << c << endl;
}
while (s != "exit");
}
which generates the following error:
error: no match for call to ‘(std::istringstream) (std::string&)’
I know that the issue may be averted by using istringstream iss(inp); within the loop, however, is it not possible to move this defintion out of the loop?
(Of course, it is possible to move it out, only that I can't accomplish anything.)
You cannot call an object constructor after the object declaration. Furthermore std::istringstream::operator ()(std::string) is not (usually) declared anywhere.
Use std::istringstream::str(…) to assign its content after construction.

stringstream: Why isn't this code returning 4?

#include <iostream>
#include <sstream>
using namespace std;
int get_4()
{
char c = '4';
stringstream s(ios::in);
s << c;
int i;
s >> i;
return i;
}
int main()
{
cout << get_4() << endl;
}
The conversion is not working for me. If I write a character '4' or character array {'4','\0'} to stringstream and then read it out to int i, I don't get back the 4. What is wrong with the above code?
Because you set the stringstream to input-only -- no output.
If you check the fail() bit after trying to extract the int, you'll see it didn't work:
s >> i;
bool b = s.fail();
if( b )
cerr << "WHOA DOGGIE! WE BLOWED UP\n";
In your code, change:
stringstream s(ios::in);
to:
stringstream s;