I'm trying to fill two arrays with an fstream. One is string and one is int. The string array (name) populates fine, but the char array only populates the first value.
void fillInventory(ifstream &fin, int costArray[],string itemArray[])
{
string name = "junk";
string cost;
int i = 0;
int max = 0;
stringstream convert;
while(name != "none")
{
getline(fin, name);
getline(fin, cost);
if(name != "none")
{
itemArray[i] = name;
convert<<cost;
convert >> costArray[i];
}
i++;
}
}
Am I using stringstream wrong or is my logic off, or something else altogether?
When you do this:
convert >> costArray[i];
You've reached the EOF on the stringstream, which sets the eofbit flag, causing future operations to fail. Reset the flags in order to continue:
convert >> costArray[i];
convert.clear();
Related
Output:
cola
coke
3
I want these values to be stored in an array. Please guide me how to!
TIA
This is the code:
int cola(string str)
{
// word variable to store word
string word;
// making a string stream
stringstream iss(str);
// Read and print each word.
while (iss >> word)
{cout << word << endl;}}
// Driver code
int main()
{
string s = "cola coke 3";
cola(s);
return 0;
}
Is this what you are looking for:
using std::string;
std::vector<string> cola(const string& str)
{
// word variable to store word
string word;
// making a string stream
stringstream iss(str);
// vector containing words
std::vector<string> temp;
// Read and print each word.
while (iss >> word)
temp.push_back(word);
return std::move(temp);
}
// Driver code
int main()
{
string s = "cola coke 3";
std::vector<string> array = cola(s);
return 0;
}
Want to read string input (from array) and save it into different variables. My code:
const string myArray[]{"4", "1 - 5", "Text_1", "Text_2", "Text_3"};
//method, which saves 1st item from myArray into line1, 2nd into line2 and the rest into line3
void Parts::saveParts(const string *myArray, int rows) {
// rows == length of myArray
istringstream iss(*myArray);
int id;
char del;
if (iss >> id >> del) {
line = id;
string rawLine2;
if (iss >> rawLine2 >> del) {
this->setLine(rawLine2);
string text;
textItems[numberOfRows-2];
if (iss >> text) {
// how can I read the rest of myArray? What should I set as 'del'?
// 'Text_1' should go into 'textItems[0]' and so on
}
}
}
else {
// here I want to throw an exception, if reading (iss >> id >> del) goes wrong (in case of id is not an integer
}
}
If the code structure itself is correct, can you direct me to completing signed if statement?
Let's say I want the user to input an integer but he enters a double or a character value, how do I check that the the user has input the correct type.
string line;
getline(cin, line);
// create stringstream object called lineStream for parsing:
stringstream lineStream(line);
string rname;
double res;
int node1,node2;
lineStream >> rname >> res >> node1 >> node2;
How do I check for valid input type?
You check the stream is OK:
if (lineStream >> rname >> res >> node1 >> node2)
{
// all reads worked.
}
You may want to check for garbage on the end.
if (lineStream >> rname >> res >> node1 >> node2)
{
char x;
if (lineStream >> x)
{
// If you can read one more character there is junk on the end.
// This is probably an error. So in this situation you
// need to do somethings to correct for this.
exit(1);
}
// all reads worked.
// AND there is no junk on the end of the line.
}
Comment expanded.
From the comments below:
if i input an integer for rname, it still works. for exmaple:
string line; getline(cin, line);
stringstream lineStream(line); // created stringstream object called lineStream for parsing
string rname;
if (lineStream >> rname) { cout << "works"; }
Lets assume there is some properties about rname that allow us to distinguish it from a number. For example: it must be a name. i.e. it must only contain alpha characters.
struct Name
{
std::string value;
friend std::istream& operator>>(std::istream& s, Name& data)
{
// Read a word
s >> data.value;
// Check to make sure that value is only alpha()
if (find_if(data.value.begin(), data.value.end(), [](char c){return !isalpha(c);}) != str.end())
{
// failure is set in the stream.
s.setstate(std::ios::failbit);
}
// return the stream
return s;
}
};
Now you can read a name.
Name rname;
if (lineStream >> rname) { cout << "works"; }
This will fail if you enter an integer for rname.
Stretch Answer
If you have multiple lines of the same information you want to read. Then it is worth wrapping it in a class and defining a input stream operator.
strcut Node
{
Name rname;
double res;
int node1;
int node2;
friend std::istream& operator>>(std::istream& s, Node& data)
{
std::string line;
std::getline(s, line);
std::stringstream linestream(line);
lineStream >> data.rname >> data.res >> data.node1 >> data.node2;
if(!linestream)
{
// Read failed.
s.setstate(std::ios::failbit);
}
return s;
}
};
Now it becomes easy to read the lines in a loop:
Node n;
while(std::cin >> n)
{
// We read another node successfully
}
Since string 123 will also be considered as string, and not an integer, so the better way is to iterate the string to end, until we find any non-digit character. here's how you may do it:
bool is_number(const std::string& s)
{
std::string::const_iterator it = s.begin();
while (it != s.end() && std::isdigit(*it)) ++it;
return !s.empty() && it == s.end();
}
Read node1 and node2 into strings first, then validate with a regular expression.
#include <regex>
...
string node1_s, node2_s;
linestream >> rname >> node1_s >> node2_s
if (regex_match(node1_s, regex("[+-]?[0-9]+") {
/* convert node1_s to int */
} else {
/* node1_s not integer */
}
/* Do same for node2_s */
My program uses a stringstream to store data to a vector of strings, which is used to pass values to a print function. The user will type in 5 items from standard input, for example: summary DAL 2 5 54. Afterwards enter is pressed and I take each of these 5 items and pass them to a summary function.
string line;
getline(cin, line);
stringstream ss(line);
string tmp;
vector<string> cmd;
int DOWN;
int TOGO;
int YDLINE;
ss >> tmp; //BEGIN INPUT
while(ss)
{
cmd.push_back(tmp); //STORE TO VECTOR OF STRINGS
ss >> tmp;
}
ss.clear();
ss.str( cmd[2] );
ss >> DOWN; //CONVERT STRING TO INT
ss.clear();
ss.str( cmd[3] );
ss >> TOGO; //STRING TO INT
ss.clear();
ss.str( cmd[4] );
ss >> YDLINE; //STRING TO INT
summary(cmd[0], cmd[1], DOWN, TOGO, YDLINE, TeamData); //PASS VALUES TO PRINT FUNCTION
I'm trying to return from the print function so that the program continues taking input after printing for as long as the user inputs data. I'm struggling with creating a proper loop. The only loop that didn't crash my program was if i did something like the following, but all it did was cause an infinite print loop.
while(ss >> tmp)
{
while(ss)
{
cmd.push_back(tmp);
ss >> tmp;
}
. . .
. . .
summary(cmd[0], cmd[1], DOWN, TOGO, YDLINE, TeamData); //PASS VALUES TO PRINT FUNCTION
}
Any advice would be greatly appreciated
It seems you want something like
while (std::getline(...))
{
// ...
while (ss >> tmp)
cmd.push_back(tmp);
// ...
summary(...);
}
stringstream.clear() is used to reset error flags and not clear the stream, although it might be giving you results but it's meaning shouldn't be changed.
#include<cstdlib>
char ch;
string line;
string buf;
bool check=true;
cout<<"Enter input\n";
while(1)
{
if(check == true)
{
cin>>line;
}
else break;
istringstream is(line);
// This will split the line based on whitespace
while(std::getline(is, buf, ' '))
{
cmd.push_back(buf);
// Checking if vector has 5 elements
if(cmd.size() == 5)
{
// Call function summary
summary(cmd[0], cmd[1], atoi(cmd[2].c_str()), atoi(cmd[3].c_str()),
atoi(cmd[4].c_str()), TeamData);
// Clear the vector list now
cmd.clear();
cout<<"Do you want to continue, enter y then"<<endl;
cin>>ch;
if(ch == 'y')
{
cout<<"Enter input"<<endl;
}
else
{
check=false;
break;
}
}
}
}
atoi function would convert your string to integer type.
I know this post has been made before on stack overflow, and I have combined various tutorials; but why does this code cause an error on execution - it does compile.
void leaderBoard::loadFromFile(void)
{
string line;
ifstream leaderBoardFile ("leaderboard.data");
vector<string> playerInfoVector;
if (leaderBoardFile.is_open())
{
while ( leaderBoardFile.good() )
{
playerInfoVector.clear();
getline (leaderBoardFile,line);
std::string input = line;
std::istringstream ss(input);
std::string token;
//cout << line << endl;
while(getline(ss, token, ',')) {
//for current line;
playerInfoVector.push_back(token);
}
string firstName = playerInfoVector.at(0);
string stringAge = playerInfoVector.at(1);
string stringScore = playerInfoVector.at(2);
//int age;
//stringstream(stringAge) >> age;
//int score;
//stringstream(stringScore) >> score;
//addScore(firstName,age,score);
////stringstream(stringAge) >> age;
////Add text to vector (push back)
playerInfoVector.clear();
}
leaderBoardFile.close();
}
else cout << "Unable to open file";
}
Yes loads of times
while ( leaderBoardFile.good() )
{
playerInfoVector.clear();
getline (leaderBoardFile,line);
should be
while ( getline (leaderBoardFile,line) )
{
playerInfoVector.clear();
It is incredible how many times this error is repeated. You actually got it right in your second while loop, so why wrong in the first one?
Unfortunately some tutorials also get this wrong.
It would also be sensible to add a check that you really do have three items in your vector. Something like this
if (playerInfoVector.size() < 3)
{
cerr << "Not enough items in player info vector\n";
exit(1);
}
string firstName = playerInfoVector.at(0);
string stringAge = playerInfoVector.at(1);
string stringScore = playerInfoVector.at(2);