istringstream not storing anything in variables - c++

I'm having an issue with istringstream not storing the values it reads. Here is what I have:
if(inputFile.good()){ //Make sure file is open before trying to work with it
//Begin Working with information
cout << "\tIn File: " << input << endl;
cout << "------------------------------------" << endl;
int number_of_lines = 0;
std::string line;
while (std::getline(inputFile, line)){
++number_of_lines;
}
Time times[number_of_lines];
double math[number_of_lines];
std::string input;
int hh, mm;
for(int loop=0;loop<number_of_lines;loop++){
std::getline(inputFile, input);
std::istringstream(input) >> mm >> hh >> math[loop];
cout << "hours = " << hh << endl;
times[loop].setTimeHours(hh);
times[loop].setTimeMinutes(mm);
times[loop].show();
cout << "*" << math[loop] << endl;
}
std::cout << "Number of lines in text file: " << number_of_lines << "\n" << endl;
}else{
cout << "Could not open file!!!" << endl;
}
The file I'm reading looks like this:
90 1 3.0
1 1 100.0
2 34 5.1
And the output when I run:
In File: data04.txt
------------------------------------
hours = 0
Operation To Be Done = 0:2336552*1.15384e-317
hours = 0
Operation To Be Done = 0:2336552*1.58101e-322
hours = 0
Operation To Be Done = 0:2336552*1.15397e-317
Number of lines in text file: 3
Anyone know why its not storing the values?

There are several key problems in this code
It doesn't check if inputs are successful. You always need to make sure you verify that the input operations worked before you process the data you read. Failing so will cause random data to be processed.
You first read to the end of the stream and then hope that the stream magically restarted. That won't work. Read the stream just once and keep appending to a std::vector<Time> (or similar container). Aside from only traversing the file once, on UNIXes the file size can change while reading.
C++ doesn't have variable sized arrays although some compiler may offer an extension similar to C's variable sized array. In C++ you'd use a std::vector<Time> instead.

First and foremost, your program is wrong. After the while loop ends, there is nothing more to read in the file (unless you seekg() back to the beginning), so the std::getline() call in the for loop body basically does nothing.
A second problem is that concerns are not properly separated.
Here is how I would have implemented this program:
struct line_data
{
Time t;
double x;
};
// This handles reading a single Time value.
std::istream & operator >> (std::istream & is, Time & t)
{
int hh, mm;
if (is >> hh >> mm)
{
// Not happy with the following two lines, too Java-like. :-(
t.setTimeHours(hh);
t.setTimeMinutes(mm);
}
return is;
}
// This handles reading a single line of data.
std::istream & operator >> (std::istream & is, line_data & ld)
{
std::string s;
if (std::getline(is, s))
{
std::istringstream iss(s);
// Ensure errors are propagated from iss to is.
if (!(iss >> ld.t >> ld.x))
is.setstate(std::ios::failbit);
}
return is;
};
// This handles processing a single line of data.
struct line_manip // satisfies concept OutputIterator<line_data>
{
std::back_insert_iterator<std::vector<Time>> ti;
std::back_insert_iterator<std::vector<double>> xi;
line_manip(std::vector<Time> & ts, std::vector<double> & xs)
: ti(std::back_inserter(ts))
, xi(std::back_inserter(xs))
{
}
line_manip & operator = (const line_data & ld)
{
ti = ld.t;
xi = ld.x;
return *this;
}
line_manip & operator * () { return *this; }
line_manip & operator ++ () { return *this; }
line_manip & operator ++ (int) { return *this; }
};
int main()
{
std::ifstream ifs("input.txt");
std::vector<Time> ts;
std::vector<double> xs;
std::copy(std::istream_iterator<line_data>(ifs),
std::istream_iterator<line_data>(),
line_manip(ts, xs));
// ...
}

Related

How to read data in text file and assign arrays each column c++

I want to learn how to read a text file (contain 3 columns 300000+ rows) and assign each column of the text file to different arrays in c++. I searched this on the internet but i could not find any suitable solution for this. I found a code to do this but the code read only 547 rows. The code is below.
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
int main() {
vector<double> vecX, vecY, vecZ;
double x, y, z;
ifstream inputFile("filetext.txt");
while (inputFile >> x >> y >> z)
{
vecX.push_back(x);
vecY.push_back(y);
vecZ.push_back(z);
}
for(int i = 0; i < vecX.size(); i++) {
cout << vecX[i] << ", " << vecY[i] << ", " << vecZ[i] << endl;
cout << i << endl;
}
}
A sample input text file data is below:
3.862015625000000e+03 5.611499505259664e-01 1.183793839633211e-02
3.862031250000000e+03 5.587474540972663e-01 1.186382272148924e-02
3.862046875000000e+03 7.376678568236076e-01 1.032568525995413e-02
3.862062500000000e+03 8.921759412061890e-01 9.389467084403112e-03
3.862078125000000e+03 8.003829513850249e-01 9.913663338280957e-03
. . .
. . .
. . .
I have one more question. The above code give an output such this: 3862.02, 0.56115, 0.0118379. But i want full digit as in the text file. How can i get.
Thanks in advance.
As mentioned in the comments, you probably have some garbage in the file and you are probably better off storing what you read in one vector.
To be able to find garbage more easily, you could throw an exception when reading fails.
Example:
#include <stdexcept>
// a class to store the values on one line in the file
struct cols_t {
double cols[3];
};
// a function to read one cols_t from a stream
std::istream& operator>>(std::istream& is, cols_t& c) {
return is >> c.cols[0] >> c.cols[1] >> c.cols[2];
}
// a function to read a stream until it's depleated, throwing an exception if it fails:
auto read_stream(std::istream& is) {
std::vector<cols_t> res;
size_t no = 0;
cols_t tmp;
while(is >> tmp) {
res.push_back(tmp);
++no;
}
if(not is.eof()) { // stream not depleated, something is wrong
is.clear(); // clear error state
std::string word;
is >> word; // and read whatever is in the stream
// throw an exception showing where the problem is
throw
std::runtime_error(
"could not read double on line " + std::to_string(no) +
", got \"" + word + "\"."
);
}
return res;
}
int main() {
std::ifstream inputFile("filetext.txt");
try {
auto vec = read_stream(inputFile);
}
catch(const std::exception& ex) {
std::cerr << ex.what() << '\n';
}
}
Setting the precision can be done using the ostreams precision() member function or using std::setprecision().
You also have a few other formatting options like std::fixed and std::scientific
If you want to be able to handle input containing -nan and nan (not a number) you can instead read the file word by word using a std::string and use std::strtod to convert the string to a double. strtod handles nans while formatted input (using >>) does not.
Example:
// a function to read one cols_t from a stream
std::istream& operator>>(std::istream& is, cols_t& c) {
std::string word;
char* end;
for(auto& v : c.cols) {
is >> word;
v = std::strtod(word.c_str(), &end); // convert word to double
if(end == word.c_str()) { // conversion to double failed
is.setstate(std::istream::failbit); // set the failbit on the stream
break; // and break out of the loop
}
}
return is;
}
// a function to read a stream until it's depleated, throwing an exception if it fails:
auto read_stream(std::istream& is) {
std::vector<cols_t> res;
size_t no = 0;
cols_t tmp;
while(is >> tmp) {
res.push_back(tmp);
++no;
}
if(not is.eof()) { // stream not depleated, something went wrong
// throw an exception showing the line with the problem
throw
std::runtime_error(
"could not read double on line " + std::to_string(no)
);
}
return res;
}
Demo

How do I write an array of contents into a text file? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 2 years ago.
Improve this question
The code is supposed to open an existing text file, transfer the contents into the array, then create a new text file and then write the array contents into the new text file. The problem I'm having is that the code only outputs the last line of the content from the new text file.
file.open("Patient.txt", ios::in);
while (!file.eof()) {
file >> arr[i].name >> arr[i].DOB >> arr[i].address >> arr[i].Dr_name >> arr[i].V_date;
/*cout << arr[i].name << arr[i].DOB << arr[i].address << arr[i].Dr_name << arr[i].V_date << endl;*/
}
file.close();
files.open("Patients_2.txt");
if (files.is_open()) {
for (i; i < 30; i++) {
files << arr[i].name << arr[i].DOB << arr[i].address << arr[i].Dr_name << arr[i].V_date;
}
}
files.close();
patientss.open("Patients_2.txt");
cout << "Patient 2: " << endl;
while (!patientss.eof()) {
getline(patientss, line);
cout << line << endl;
}
patientss.close();
system("pause");
return 0;
}
IMHO, you should overload the formatted insertion and extraction operators in your patient class:
struct Patient
{
std::string name;
std::string dob;
std::string address;
std::string dr_name;
std::string v_date;
friend std::istream& operator>>(std::istream& input, Patient& p);
friend std::ostream& operator<<(std::ostream& output, const Patient& p);
};
std::istream& operator>>(std::istream& input, Patient& p)
{
std::getline(input, p.name);
std::getline(input, p.dob);
std::getline(input, p.address);
std::getline(input, p.dr_name);
std::getline(input, p.v_date);
return input;
}
std::ostream& operator<<(std::ostream& output, const Patient& p)
{
output << p.name << "\n";
output << p.dob << "\n";
output << p.address << "\n";
output << p.dr_name << "\n";
output << p.v_date << "\n";
return output;
}
The above makes input and output easier:
std::vector<Patient> database;
Patient p;
while (input_file >> p)
{
database.push_back(p);
}
const unsigned int quantity = database.size();
for (unsigned int i = 0; i < quantity; ++quantity)
{
output_file << database[i];
}
The above code also supports the concepts of encapsulation and data hiding. The Patient struct is in charge or reading its members because it knows the data types of the members. The code external to the Patient is only concerned with the input and output of a Patient instance (doesn't care about the internals).
This loop has a few problems:
while (!file.eof()) {
file >> arr[i].name >> arr[i].DOB ....
You never increase i so the same arr[i] will be overwritten time and time again.
You use !file.eof() as a condition to stop reading. eof() does not get set until after you've tried to read beyond the end of the file, which means that if you had increased i as you should, the last arr would be empty / broken. Instead check if the extraction from the stream succeeded. Since the stream is returned when you do stream >> var and has an overload for explicit operator bool() const which returns !fail() you can do this check directly in your loop:
while(stream >> var) { extraction success }
Using formatted input (>>) for string fields that are likely to contain spaces is however not a good idea. Your name, nung khual, would be split so nung would go into name and khual would go into DOB. It's better to use a field separator that is very unlikely to be included in anyone's name. \n is usually good and works well with std::getline.
std::getline returns the stream that you gave as an argument which means that you can chain getlines similarly to stream >> var1 >> var2, except it's a little more verbose.
getline(getline(stream, var1), var2) will put the first line in var1 and the second line in var2.
To make input and output a little simpler you can add stream operators for your data type and make the input stream operator use getline for your fields.
Example:
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
struct data_t {
std::string name;
std::string DOB;
std::string address;
std::string Dr_name;
std::string V_date;
};
// input stream operator using chained getlines
std::istream& operator>>(std::istream& is, data_t& d) {
using std::getline;
return getline(getline(getline(getline(getline(is,
d.name), d.DOB), d.address), d.Dr_name), d.V_date);
}
// output stream operator
std::ostream& operator<<(std::ostream& os, const data_t& d) {
return os << d.name << '\n'
<< d.DOB << '\n'
<< d.address << '\n'
<< d.Dr_name << '\n'
<< d.V_date << '\n';
}
int main() {
std::vector<data_t> arr;
if(std::ifstream file("Patient.txt"); file) {
data_t tmp;
while(file >> tmp) { // remember, no eof() needed
arr.push_back(tmp);
}
}
if(std::ofstream file("Patients_2.txt"); file) {
for(const data_t& d : arr) {
file << d;
}
}
if(std::ifstream patientss("Patients_2.txt"); patientss) {
data_t tmp;
while(patientss >> tmp) {
std::cout << tmp;
}
}
}

C++ how to validate input for use with overloaded >> operator

I am writing a program that can do operations on complex numbers. I have a class called ComplexNumber that has the overloaded operators in it. My program takes input from a file in the form of complex *operator* complex. So, for example an input would look like 3+4i + 2+3i. I have written my >> operator so this works fine.
The issue arises when the input looks like 3i + 1+2i. We have to validate the input so it works when the complex number is missing parts. It can be just a real number, or just an imaginary number.
The functions in the ComplexNumber class that relate to this issue are as follows:
ComplexNumber::ComplexNumber(double r,double i)
{
realNum = r;
imaginaryNum = i;
}
istream& operator>>(istream &input , ComplexNumber& other) //Overloaded >> operator
{
char filter = 0;
double r =0;
double i = 0;
input >> r >> i >> filter;
other.setR(r);
other.setI(i);
return input;
}
And the way I am reading in the input in my main class is as follows:
void input(ifstream &in)
{
ComplexNumber a,b;
in >> a;
in.get();
string op;
getline(in,op,' ');
in >> b;
cout << a << " " << op << " " << b << endl;
}
int main()
{
ifstream in("complex.txt");
if(!in) cout << "failed to open file." << endl;
while(!in.eof()){
input(in);
}
return 0;
}
For my operators to work, I need to set the missing part of the input as 0 in the object. So if the input was 3i the variables in the object would be realNum = 0, imaginaryNum = 3 How can I achieve this?
How can I check the input on the line to decide how it should be read in? At the moment, it is expecting the complex number to have both a real and imaginary part to it.
I also wrote an overloaded constructor for cases where the complex number only has one of the parts to it, but I am unsure how to use it. The function is as follows:
ComplexNumber::ComplexNumber(double in, string r_i) //Overloaded constructor
{
if(r_i == "r"){realNum = in; imaginaryNum = 0;}
else{imaginaryNum = in; realNum = 0;}
}
Beyond this issue, we also have to check to make sure that the input has no invalid characters eg. j or ! but i feel that if I get help with this first problem, I can use the information given to solve this second problem.
I realize that this may not be worded in the best way, I just hope you understand what I am trying to achieve. I really appreciate any help with this. Thanks.
Normally I'd do this with a state machine. Never done it with C++ streams before. Bit sneakier than it looked, but basically the same. Commentary on the whats and whys embedded as comments in the code.
#include <string>
#include <iostream>
#include <sstream>
#include <cmath>
#include <cctype>
// Made this really dumb for ease of writing example
struct ComplexNumber
{
double realNum;
double imaginaryNum;
};
// splitting the guts of the parsing off into its own function made writing
// operator>> dead easy
bool parsecomplex(std::istream &input,
double & real,
double & imag)
{
char filter;
double temp;
char next;
if (input >> temp)// read a double. No clue if it's the real or imaginary part yet.
{
next = input.peek(); // check the next character, but do not extract
if (next != 'i') // not imaginary
{
real = temp; // store as real
if (next == '+' || next == '-') // do we stop here or is there an imaginary?
{
if (input >> imag >> filter // read imaginary
&& filter == 'i') // and ensure trailing i
{
return true;
}
}
else
{
return true;
}
}
else
{ // just an imaginary
imag = temp;
input >> filter; // remove the i. we already know it's an i
return true;
}
}
return false;
}
std::istream& operator>>(std::istream &input,
ComplexNumber& other)
{
double real = 0.0;
double imag = 0.0;
if (parsecomplex(input, real, imag))
{ // OK so we got a good complex number.
other.realNum = real;
other.imaginaryNum = imag;
input.clear(); // may have read eof
return input;
/* This next bit is a deviation from normal stream parsing. Typically 3j
would be read and store of 3 as real and j stays in the stream for the
next read. OP sounds like they might need to be a bit more anal. If so,
replace the above with
char next = input.peek();
if (std::isspace(next) || next == std::char_traits<char>::eof())
{
other.realNum = real;
other.imaginaryNum = imag;
input.clear(); // may have read eof
return input;
}
The Law of Least Surprise says you should go with the expected parsing
behaviour so as to not leave a trail of confused and angry programmers
in your wake. */
}
input.setstate(std::ios::failbit);
return input;
}
// quick test harness
void test(const char * str)
{
ComplexNumber cnum;
std::stringstream input(str);
if (input >> cnum)
{
std::string remaining;
std::getline(input, remaining);
std::cout << str << " is " << cnum.realNum <<","<< cnum.imaginaryNum
<< " still in stream: " << remaining << std::endl;
}
else
{
std::cout << "Invalid: " << str << std::endl;
}
}
int main()
{
test("3-3i");
test("3");
test("-3i");
test(" 3-3i");
test("3-3i ");
test("3 ");
test("-3i ");
test("3-3i 3-3i");
test("3 -3i");
test("j3+3i");
test("3j3i");
test("3+3j");
test("3+3ij");
test("3j");
test("-3j");
test("-3ij");
test("");
test("DETHTONGUE!");
}
Output:
3-3i is 3,-3 still in stream:
3 is 3,0 still in stream:
-3i is 0,-3 still in stream:
3-3i is 3,-3 still in stream:
3-3i is 3,-3 still in stream:
3 is 3,0 still in stream:
-3i is 0,-3 still in stream:
3-3i 3-3i is 3,-3 still in stream: 3-3i
3 -3i is 3,0 still in stream: -3i
Invalid: j3+3i
3j3i is 3,0 still in stream: j3i
Invalid: 3+3j
3+3ij is 3,3 still in stream: j
3j is 3,0 still in stream: j
-3j is -3,0 still in stream: j
-3ij is 0,-3 still in stream: j
Invalid:
Invalid: DETHTONGUE!

getting selected data from a vector then storing as a variable

Ive currently stored all my data into a vector as variables. im trying to get selected data from that vector, storing then as variables so i can then do calculations, save the answers as a variable to then store back in my original vector?
The data file is in the format below;
a b c d e
1 7.3 0.8 14 74.6
2 6.5 0.1 13 3.3
3 10.8 1.4 12 75.8
4 13.2 3.5 6 32.4
my code is as below so far;
struct Weather
{
int a_data;
double b_data;
double c_data;
int d_data;
double e_data;
double ans_data;
};
int main ()
{
using std::vector;
using std::string;
using std::getline;
using std::cout;
vector<Weather> data_weather;
string line;
ifstream myfile ("weatherdata.txt");
if (myfile.is_open())
{
int count = 0;
while (getline(myfile, line))
{
if (count > 6)
{
int a, d;
double b, c, e;
std::istringstream buffer(line);
std::string sun_as_string;
if (buffer >> a >> b >> c >> d >>e_as_string)
{
if (e_as_string == "---")
{
e = 0.0;
}
else
{
std::istringstream buffer2(e_as_string);
if (!(buffer2 >> e))
{
e = 0.0;
}
}
Weather objName = {a, b, c, d, e};
data_weather.push_back(objName);
}
}
count++;
}
myfile.close();
double temp_b, temp_c, temp_ans; //declaring my new variables
for (auto it = data_weather.begin(); it != data_weather.end(); ++it)
{
std::cout << it->b_data << " " << it->c_data << std::endl;
}
}
}
else
cout << "unable to open file";
scat::pause("\nPress <ENTER> to end the program.");
return 0;
}
any help would be appreciated
Am missing something obvious or do you simply need to do this?
for (auto it = data_weather.begin(); it != data_weather.end(); ++it)
{
it->ans_data = it->b_data * it->c_data;
}
Dereferencing an iterator gives you a reference to an existing object inside the vector. You don't really need temporary variables for this.
A nicer C++11 alternative is a range based for loop:
for (Weather& w : data_weather)
{
w.ans_data = w.b_data * w.c_data;
}
Given a list of indices of lines you want to work with, you can do something like this:
Weather& w = data_weather[i]; // shortcut so you don't need to
// write data_waether[i] each time
w.ans_data = (w.b_data * w.c_data)/2;
where i is the index of the line your interested in. You might want to put this is some kind of a loop. I leave that as an exercise for you :)
I would structure this somewhat differently. I'd write the code for reading the data as an operator>> for the Weather structure:
std::istream &operator>>(std::istream &is, Weather &w) {
std::string line;
std::getline(is, line);
std::istringstream buffer(line);
buffer >> w.a >> w.b >> w.c >> w.d;
if (!buffer >> w.e) // conversion will fail for "---" or not-present
w.e = 0.0;
return is;
}
This can simplify reading the data:
std::ifstream myfile("Weather.txt");
std::string ign;
std::getline(myfile, ign); // skip that pesky first line
// Now we can initialize the vector directly from the data in the file:
std::vector<Weather> weather_data((std::istream_iterator<Weather>(myfile)),
std::istream_iterator<Weather>());
With a reasonably recent compiler, printing out the data can be simplified as well:
for (auto &w : weather_data)
std::cout << w.b_data << " " << w.c_data << "\n";
If you want to do a calculation, and put a result back into the ans field of your structure, that's fairly easy also. For example, let's assume b, c and d are temperatures, and we want ans to contain the average of the three:
for (auto &w : weather_data)
w.ans = (w.b_data + w.c_data + w.d_data)/3.0;

Read a file twice in C++ because of eof?

I read numbers from a file, apply 3 functions and print out to another file:
int main(int argc, char** argv) {
std::ifstream fin;
fin.open("input.txt");
std::ofstream fout;
fout.open("output.txt", std::ios::app);
char arr[50];
int a,b;
int N;//number to factor
while (!fin.eof()){
//Print backward
fin >> arr;
PrintBackward( arr );
fout << endl;
//Greatest common divisor
((fin >> a) >> b);
fout << gcd( a, b );
fout << endl;
//Find prime factor
fin >> N;
PrimeFactor(N);
fout << endl;
}
fin.close();
fout.close();
return 0;
}
After running, the result is duplicated:
olleh
3
2 3 7
olleh
3
2 3 7
I read a similar article but it's about reading into 1 variable so it seems not to be feasible.
If I set a break at the end of the while loop, it's fine. Is there any way not to use break?
while (!whatever.eof()) is essentially always wrong, and will never detect the end of the file correctly. In your case, it's easiest to coalesce the reads together, and then do all the processing, something like this:
while (fin >> arr >> a >> b >> N) {
PrintBackwards(arr);
fout << "\n";
fout << gcd(a, b) << "\n";
fout << PrimeFactor(N) << "\n";
}
The crucial part is to check the result of the read, instead of checking and reading separately from each other.
A couple more bits of advice: I'd use an std::string instead of an array. I'd also separate reversing the string from printing it, so you can have something like:
fout << reverse(arr) << "\n"
<< gcd(a, b) << "\n"
<< PrimeFactor(N) << "\n";
Emphasizing the commonality between the operations tends to be a good thing.
Edit: Just for fun, I'll point out another way you could do things if you wanted. Since you're basically reading and processing the four items as a group, you could make that grouping a bit more explicit:
struct item {
std::string arr;
int a, b, N;
friend std::istream &operator>>(std::istream &is, item &i) {
return is >> arr >> a >> b >> N;
}
};
struct process {
std::string operator()(item const &i) {
std::ostringstream buffer;
buffer << reverse(arr) << "\n" << gcd(a, b) << "\n" << PrimeFactor(N);
return buffer.str();
}
}
With this, you can let the standard library deal with all the details of the reading and writing, checking end of file, etc.:
std::transform(std::istream_iterator<item>(fin),
std::istream_iterator<item>(),
std::ostream_iterator<std::string>(std::cout, "\n"),
process());
My guess is that you're checking eof too early - it's only set when you try to read and the read fails because you're at the end of the file. Try adding this after fin >> arr:
if (fin.eof()) break;
Actually you should be checking for errors after every IO operation - not to do so is sloppy coding and won't be robust.