What does >> do when used with string stream? - c++

I was reading the following code sample:
std::array<int, 4> parseMessage(const std::string& input) {
std::stringstream ss(input);
std::array<int, 4> message;
int n;
// Loop over all characters in the string and ignore the semicolons.
for (int i = 0; ss >> n && i < 4; ++i) {
message[i] = n;
if (ss.peek() == ';') {
ss.ignore();
}
}
return message;
}
Can someone explain why someone would do ss>>n in the loop condition area ? It looks a bit odd to me.

It will first read a an int from the stream and then evaluate if the stream is good. (because s >> n will return a reference to s).
Evaluating a stream as bool:
Returns true if the stream has no errors and is ready for I/O operations. Specifically, returns !fail().
So as soon as the stream fails to read an int or reaches the end of stream (e.g. end of input) it will evaluate as false and end the loop.
So this code will extract up to 4 ints from a given input (4, because of the && i < 4).

>> reads into the variable on the right hand side of the expression and returns the stream.
Using a stream in a boolean expression returns whether the stream has not failed.
Your for loop is therefore equivalent to:
int i = 0;
while ( i < 4 )
{
ss >> n;
if ( ss.fail() )
{
break;
}
message[i] = n;
if (ss.peek() == ';') {
ss.ignore();
}
i++;
}
It reads up to 4 numbers and stops if the contents of the stream are not convertible to a number.

Related

How to read multiple integers from string

INPUT:
Mint Ice Cream 6 80
CODE:
int IntAmount=2;
string line, name, data;
ifstream fd('Input.txt);
getline(fd, line);
name=line.substr(0, 20); // name="Mint Ice Cream "
data=line.substr(20); // data ="6 80"
for(int i=0; i<IntAmount; i++){
// code that reads N[i] integer by integer from string called data
}
I got some integers stored in the same string data. How do I extract them into array N[i] if I know there are IntAmount of them? I know that I can read the Input in much more basic way, but this is just very simplified input.
Following function will do the job for you:
int string_to_int(char const *input_str, std::size_t count)
{
int result_integer = 0;
std::size_t i = 0 ;
if ( input_str[0] == '+' || input_str[0] == '-' )
++i;
while(i < count)
{
if ( input_str[i] >= '0' && input_str[i] <= '9' )
{
int val = (input_str[0] == '-') ? ('0' - input_str[i] ) : (input_str[i]-'0');
result_integer = result_integer * 10 + val;
}
else
throw std::invalid_argument("invalid string input");
i++;
}
return result_integer;
}
EDIT: nevermind I thought it was C#
You could split the data string into multiple strings as such data.Split(' ') (which splits it at the ' '-character) and then for each substring it returns you can use the function int.Parse(<substring here>) to get the integer equivalent for it.

Multiple conditions in while loop using &&

What works:
ifstream in("CallHello.cpp");
while(in >> s) {
if(s=="cout")
count++;
}
cout<<"Number of words : "<<count<<endl;
Output is 1 here which is correct.
What doesn't work
ifstream in("CallHello.cpp");
while(in >> s && s == "cout") {
count++;
}
cout<<"Number of words : "<<count<<endl;
Output is 0, for the above which is wrong.
Why adding another condition in the while using && gives the wrong output?
the first condition will continue looping while in has something to put on s, the second condition where you use while(in >> s && s == "cout") will only work if the first time you retrieve a value for s has a string of "cout" then it will run the block, therefore, your first value in s is not also "cout" the first time, so it just never loops.
Here is the reason why:
string s;
int count = 0;
while (in >> s && s == "cout") { // Ops: s == ""
++count; // while condition is false!
} // loop is skipped!
cout<<"Number of words : "<<count<<endl; // count was never incremented
// Output is 0

how to read characters and integers from a file?

So I have a data file that looks something like this:
x + y + z
30 45 50
10 20 30
The only characters I needed was the operators, so '+' '+' I was able to use file.get() to successfully get those characters and put them in an array. Problem is I need to get the next line of numbers, and assign them to the values x , y z . I know I cant use .get() , I would have to use getline. Will i have to eliminate the file.get() and use getline instead for first part also?
I looked at some of the questions posted on here but none of them were quite like mines. Note I'm actually going to be using these values for another part of my program, just used cout to see if my values were being read correctly
Here's my previous code:
main(int argc, char *argv[])
{
int a=0;
int n;
fstream datafile;
char ch;
pid_t pid;
int a, b, c, result;
string line;
datafile.open("data1.txt");
if(datafile)
{
for(int i=0; i <9; i++)
{
datafile.get(ch);
if (ch == '*'||ch == '/'||ch == '+'||ch == '-')
{
operations[a] = ch;
cout<<operations[a];
a++;
}
}
}
else
cout<<"Error reading file";
}
So this is how I was getting the first line of the file in the beginning. It worked like I wanted it to, may have not been the nicest coding but it worked. Nevertheless I tried to get the rest of the file, this time using getline, but instead of getting the numbers I was getting a bunch of random gibberish/numbers. I know if I use getline, the first line cannot be in my loop. I know this is how I would get the numbers.
while(getline(datafile, line))
{
istringstream ss(line);
ss >> x >> y >> z;
cout<<x<<""<<y<<""<<z;
}
Would the following make sense for the first line, or am I missing something:
string input;
std::getline(datafile, input)
for (int i = 0; i < input.size(); i++)
if (input[i] == '+' || ...)
{
operations[a] = input[i];
a++;
}
If you don't want to use getline, you could simply read the entire file stream (note that the bool is a rather naive way to handle the problem, I'd recommend something more elegant in your actual code):
bool first = true;
string nums;
int lines = 0;
vector<vector<int>> numlines;
vector<int> topush;
while (!datafile.eof())
{
char ch = datafile.get()
if (ch == 12 && first) //I don't know if '\n' is valid, I'd assume it is but here's the sure bet
first = false;
else if (first && (ch == '+' || ...))
{
operator[a] = ch;
a++;
}
else if (!first && (ch >= '0' && ch <= '9'))
{
if (!(datafile.peek() >= '0' && datafile.peek() <= '0'))
{
numlines[lines].push_back(atoi(nums.c_str());
nums.clear();
if (datafile.peek() == 12)
{
numlines.push_back(topush);
lines++;
}
}
else
nums = nums + ch;
}
Honestly, I can't be sure the above will work exactly right, I'd recommend you just modify your code to use getline exclusively. You'll need to add #include to get atoi.
Add this to your code:
while(!datafile.eof()){
string s;
getline(datafile, s);
istringstream in(s);
string tmp;
while(in >> tmp){
int i = stoi(tmp)
//Do something with i....
}
}

c++ parse string using multiple delimiters using inbuilt c/c++

I am trying to parse a string that looks like "1,4-6,8-10,12" and push_back the results into a vector of ints/char*. While parsing, if the logic comes across 4-6 then it should push the ints 4,5 and 6 in the vector. I am trying to do this using strtok but it modifies the only copy of the input string so I am not getting anywhere. I cannot use boost or else tokenizer would have been very easy and useful.
#include <stlport\sstream>
#include <stlport\vector>
using namespace std;
...
stringstream ss("1,4-6,8-10,12");
vector<int> v;
int x, x2;
char c;
while (ss >> x)
{
v.push_back(x);
if (!(ss >> c))
break; // end of input string
if (c == '-')
{
if (!(ss >> x2))
throw; // incorrect input string
for (int i = x+1; i <= x2; i++)
v.push_back(i);
if (!(ss >> c))
break; // end of input string
}
else if (c != ',')
throw; // incorrect input string
}
// check
int s = v.size();
// s = 8, v:{1,4,5,6,8,9,10,12}
std::stringstream ss("1,4-6,8-10,12");
std::vector<int> v;
int x;
while(ss >> x)
{
v.push_back(x);
char c;
ss >> c; //will just discard a non space char.
if(c != ',' || c != '-') ss.unget(); //... unless is just , or -
}
Time to write this: 1 minute.
Time to search for an appropriate algorithm function: 5 minutes at least.
Decide yourself what's more productive.

read an input file using vectors

I have written a code to read file below but its not working.
Input file:
2 1 16
16 0 0
1 1 1234
16 0 0
1 1 2345
code is:
std::ifstream input_file;
evl_wire wire;
int num_pins,width,cycles,no;
std::vector<int>IP;
while(input_file)
{
input_file >> num_pins;//num_pins=2
if (pins_.size() != num_pins) return false;
for (size_t i = 0; i < pins_.size(); ++i)
{
input_file >> width;//width=1 for 1=0 ,=16 for i=2
if (wire.width != width) return false;
pins_[i]->set_as_output();
}
for (size_t i = 1; i < file_name.size(); i=i+1)
input_file>>cycles;
input_file>>no;
pins_=IP;
}
where std::vector<pin *> pins_; is in gate class and void set_as_output(); is in pin class
2 represent no of pins,1 width of first pin and 16 width of second pin.
here from second line in file 16 is no of cycles pins must remain at 0 0,for next 1 cycle pins must be assigned 1 and 1234 as inputs.
Some parts of your code are almost certainly wrong. Other parts I'm less certain about -- they don't make much sense to me, but maybe I'm just missing something.
while(input_file)
This is almost always a mistake. It won't sense the end of the file until after an attempt at reading from the file has failed. In a typical case, your loop will execute one more iteration than intended. What you probably want is something like:
while (input_file >> num_pins)
This reads the data (or tries to, anyway) from the file, and exits the loop if that fails.
if (pins_.size() != num_pins) return false;
This is less clear. It's not at all clear why we'd read num_pins from the file if we already know what value it needs to be (and the same seems to be true with width vs. wire.width).
for (size_t i = 1; i < file_name.size(); i=i+1)
input_file>>cycles;
This strikes me as the most puzzling part of all. What does the size of the string holding the file name have to do with anything? This has be fairly baffled.
I don't fully understand your code, but I don't see you are opening the input file anywhere. I think it should be:
std::ifstream input_file;
evl_wire wire;
int num_pins,width,cycles,no;
std::vector<int>IP;
input_file.open("name of the file");
if(input_file.is_open())
{
while(input_file >> num_pins) //num_pins=2
{
if (pins_.size() != num_pins) return false;
for (size_t i = 0; i < pins_.size(); ++i)
{
input_file >> width;//width=1 for 1=0 ,=16 for i=2
if (wire.width != width) return false;
pins_[i]->set_as_output();
}
for (size_t i = 1; i < file_name.size(); i=i+1)
input_file>>cycles;
input_file>>no;
pins_=IP;
}
input_file.close();
}
The function I used:
bool input::validate_structural_semantics()
{
evl_wire wire;
std::ifstream input_file;std::string line;
int x[]={1000};
for (int line_no = 1; std::getline(input_file, line); ++line_no)
std::string s; int i=0;
std::istringstream iss;
do
{
std::string sub;
iss >> sub;
x[i]=atoi(sub.c_str());
i++;
}
while (iss);
if (pins_.size()!=x[0]) return false;
for (size_t i = 0; i < pins_.size(); ++i)
{
if (wire.width != x[i+1]) return false;
pins_[i]->set_as_input();
}
for(size_t i=4;i<1000;i++)
{
for(size_t j=0;j<pins_.size();j++)
pins_.assign(x[i-1],x[i+j]);
}
return true;
}
This implementation is using arrays but it didn't work,although there isn't any compling error.