Using fscanf

I have a .txt file which looks like the following (the real file has many more lines, but this will suffice for discussion of my problem):

# mass,pressure, temperature,radius,density
1.897999999999999950e+27 9.999999999999999167e-02 1.650000000000000000e+02 6.991000000000000000e+07 1.468454784270681912e-07
1.897999999999999675e+27 1.000761464025201886e-01 1.650000000000000000e+02 6.990998000000000000e+07 1.469572959761539566e-07
1.897999999999999400e+27 1.001523508314045990e-01 1.650000000000000000e+02 6.990996000000000000e+07 1.470691987343319133e-07
1.897999999999999125e+27 1.002286133309046728e-01 1.650000000000000000e+02 6.990994000000000000e+07 1.471811867665832263e-07

As can be seen, it has one commenting line and subsequent rows with numeric data. I have been trying to import this data in my C++ program, but have been facing issues. My current C++ program does not import this data well; I have tested this with a printf statement to see what values were being imported. My current source code looks as follows:

#include <iostream>
#include <fstream>
#include <math.h>
#include <vector>
#include <array>
#include <string>
#include <algorithm>
#include <cstdio>

using namespace std;

int main(){
vector <double> m_range;
vector <double> p_range;
vector <double> T_range;
vector <double> r_range;
vector <double> rho_range;
double m_range_val;
double p_range_val;
double T_range_val;
double r_range_val;
double rho_range_val;

FILE *ifile;
ifile = fopen("/data/vault/ap817/Accretion/Umbrella_scripts/project_scripts/planetary_structure_params.txt","r");
if (ifile != NULL){
printf("printing m_range %lf", m_range_val); //this is to test the garbage value from the instantiation above
while (fscanf(ifile, "%lf %lf %lf %lf %lf\n", &m_range_val,&p_range_val,&T_range_val,&r_range_val,&rho_range_val) != EOF){ //fscanf returns the number of items read, nothing else. if it
m_range.push_back(m_range_val);
p_range.push_back(p_range_val);
T_range.push_back(T_range_val);
r_range.push_back(r_range_val);
rho_range.push_back(rho_range_val);

}
fclose(ifile);
}
else{
void exit();
}
return 0;}

Is there a glaring problem? Might it be that I need a space between the %f's? How can I skip the comment line and go straight to the numbers?
You need to skip the first line (with fgets) or remove it from the file before you can read the values.
fscanf() will fail and return 0 (not EOF) on the first line. You really should check for success (result = 5), not a specific failure condition (result = EOF). If I remove the comment line at the time, the code works fine.

But why are you using fscanf() at all? It would be much safer and easier to do this with streams.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <fstream>
#include <sstream>
#include <math.h>
#include <vector>
#include <string>
#include <algorithm>
#include <cstdio>

using namespace std;

int main(){
    vector <double> m_range;
    vector <double> p_range;
    vector <double> T_range;
    vector <double> r_range;
    vector <double> rho_range;
    double m_range_val;
    double p_range_val;
    double T_range_val;
    double r_range_val;
    double rho_range_val;

    ifstream ifile("params.txt");
    string line;
    int result;
    if (!ifile) {
        cerr << "Can't open input file\n";
        return 1;
    }
    while (getline(ifile, line)) {
        // skip blank lines and lines that begin with '#'
        if (line.size() == 0 || line[0] == '#') {
            cerr << "Skipping line: " << line << '\n';
            continue;
        }

        // Now create an istream and read the data.
        istringstream is(line);
        is >> m_range_val >> p_range_val >> T_range_val
           >> r_range_val >> rho_range_val;

        // Make sure the reade was successful
        if (!is) {
            cerr << "bad line: " << line << '\n';
            continue;
        }

        // If you get here then you successfully read the line.
        m_range.push_back(m_range_val);
        p_range.push_back(p_range_val);
        T_range.push_back(T_range_val);
        r_range.push_back(r_range_val);
        rho_range.push_back(rho_range_val);

        cout << "read "
             << m_range_val << ' '
             << p_range_val << ' '
             << T_range_val << ' '
             << r_range_val << ' '
             << rho_range_val << '\n';
    }
    return 0;
}

Here I used a class (or struct if you like) to hold the data for each line in the file.
Also, the comment lines are ignored by default since the non-numeric data will not satisfy the requirement. It would be better to specifically reject lines which commence with a '#'.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sstream>
#include <vector>

class Planet {
public:
    double mass;
    double pressure;
    double temperature;
    double radius;
    double density;
};

int main()
{
    std::ifstream fin("planetary_structure_params.txt");
    if (!fin)
    {
        std::cout << "File not open\n";
        return 1;
    }
    
    std::vector<Planet> planets;
    
    std::string line;
    while (getline(fin, line))
    {
        std::istringstream ss(line);
        Planet planet;
        if (ss >> planet.mass >> planet.pressure >> planet.temperature >> planet.radius >> planet.density)
            planets.push_back(planet);
    }
    
    std::cout << "Number of rows read: " << planets.size() << '\n';
    std::cout << std::scientific << std::setprecision(10);
    
    for (unsigned int i=0; i< planets.size(); i++)
        std::cout << std::setw(25) << planets[i].mass 
                  << std::setw(25) << planets[i].pressure 
                  << std::setw(25) << planets[i].temperature 
                  << std::setw(25) << planets[i].radius 
                  << std::setw(25) << planets[i].density 
                  << '\n';
}


Number of rows read: 4
        1.8980000000e+027        1.0000000000e-001        1.6500000000e+002        6.9910000000e+007        1.4684547843e-007
        1.8980000000e+027        1.0007614640e-001        1.6500000000e+002        6.9909980000e+007        1.4695729598e-007
        1.8980000000e+027        1.0015235083e-001        1.6500000000e+002        6.9909960000e+007        1.4706919873e-007
        1.8980000000e+027        1.0022861333e-001        1.6500000000e+002        6.9909940000e+007        1.4718118677e-007
Last edited on
Topic archived. No new replies allowed.