2
\$\begingroup\$

I am an artist and a total beginner in C++.

I would like to find a better method of importing my variables from a values.txt file, which may contain 18 values in one column:

63.64474122
5.214728341
0.405110193
0.261556475
-2.00743E-09
2.76001E-10
34.45902482
15.62249852
0.220861685
2.88127E-09
0.445804979
2.76001E-10
82.11020306
14.02709406
0.507487944
2.88127E-09
-2.00743E-09
0.159178722

… or it could contain three rows of six tab-separated columns:

63.64474122 5.214728341 0.405110193 0.261556475 -2.00743E-09    2.76001E-10
34.45902482 15.62249852 0.220861685 2.88127E-09 0.445804979 2.76001E-10
82.11020306 14.02709406 0.507487944 2.88127E-09 -2.00743E-09    0.159178722

I know my code is ugly. Could somebody help?

#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;

#define PI 3.14159265

//___________________________________________________

/// variables from the *.txt file 

double x_A = 0;
double y_A = 0;
double d_A = 0;
double m_A = 0;
double c_A = 0;
double t_A = 0;
double x_B = 0;
double y_B = 0;
double d_B = 0;
double m_B = 0;
double c_B = 0;
double t_B = 0;
double x_C = 0;
double y_C = 0;
double d_C = 0;
double m_C = 0;
double c_C = 0;
double t_C = 0;

//__________________________________________________

int trash    = 0;   

//___________________________________

int main() {

    ifstream ifs ("values.txt"); ///LOADING
    if (!ifs)
    // process error
    ifs >> trash;
    ifs >> x_A;
    ifs >> y_A;
    ifs >> d_A;
    ifs >> m_A;
    ifs >> c_A;
    ifs >> t_A;
    ifs >> x_B;
    ifs >> y_B;
    ifs >> d_B;
    ifs >> m_B;
    ifs >> c_B;
    ifs >> t_B;
    ifs >> x_C;
    ifs >> y_C;
    ifs >> d_C;
    ifs >> m_C;
    ifs >> c_C;
    ifs >> t_C;

cout << x_A << endl;
cout << y_A << endl;
cout << d_A << endl;
cout << m_A << endl;
cout << c_A << endl;
cout << t_A << endl;
cout << x_B << endl;
cout << y_B << endl;
cout << d_B << endl;
cout << m_B << endl;
cout << c_B << endl;
cout << t_B << endl;
cout << x_C << endl;
cout << y_C << endl;
cout << d_C << endl;
cout << m_C << endl;
cout << c_C << endl;
cout << t_C << endl;

}
\$\endgroup\$
  • \$\begingroup\$ As a fly-by comment, it seems like this should possibly be something like a struct xydmct { double x, y, d, m, c, t; } with appropriate constructor, operator>> and operator<< functions. This would cut down on the repetition or allow it to be placed in a container such as a vector. Would you need help figuring out how to do that? \$\endgroup\$ – Michael Urman Nov 14 '13 at 3:43
4
\$\begingroup\$

Storing the data in 18 independent variables is awkward. The naming of your variables suggests that each group of six doubles represents an object, which I've called a Sexdoublet.

Throwing all the code into main() is poor practice; there should be a function to do the importing. It should accept an istream parameter and return a vector of Sexdoublets.

I don't know what you were hoping to accomplish with if (!ifs) ifs >> trash; — if the ifstream is bad then you shouldn't try reading from it.

Hard-coding the filename is probably a bad idea. I've used the convention of reading from either a file that is specified on the command line, or from standard input otherwise.

#include <fstream>
#include <iostream>
#include <string.h>
#include <vector>

/* A struct of six doubles */
struct Sexdoublet {
    double x, y, d, m, c, t;

    friend std::istream &operator>>(std::istream &in, Sexdoublet &r) {
        return in >> r.x >> r.y >> r.d >> r.m >> r.c >> r.t;
    }

    friend std::ostream &operator<<(std::ostream &out, const Sexdoublet &r) {
        return out << "[ x = " << r.x
                   << ", y = " << r.y
                   << ", d = " << r.d
                   << ", m = " << r.m
                   << ", c = " << r.c
                   << ", t = " << r.t << " ]";
    }
};

std::vector<Sexdoublet> import(std::istream &in) {
    std::vector<Sexdoublet> data;
    Sexdoublet s;
    while (in >> s) {
        data.push_back(s);
    }
    return data;
}

int main(int argc, char *argv[]) {
    // If the first command-line argument is not "-", treat it as the filename
    // from which to read the input.  Otherwise, read from STDIN.
    const char *filename = (argc >= 2 && 0 != strcmp("-", argv[1])) ?
                                argv[1] : NULL;
    std::ifstream f;
    std::istream &in = filename ? (f.open(filename), f) : std::cin;
    if (!f) {
        std::cerr << "Error opening " << filename << ": "
                  << strerror(errno) << std::endl;
        return 1;
    }

    std::vector<Sexdoublet> data = import(in);
    std::for_each(data.begin(), data.end(), [](const Sexdoublet &s) {
        std::cout << s << std::endl;
    });
    return 0;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.