Search code examples
c++iosegmentation-faultfstream

Segmentation fault related to ofstream


I'm stumped on this one...can't seem to find a solution anywhere...

I have a class SAR composed of SARdataPoints. SAR calculates analysis values related to stock prices contained in SARdataPoints.

#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include <array>
#include "SARdataPoint.h"
#include "SAR.h"

using namespace std;

int main()
{

array<string, 10> files = {"/home/reechee/Documents/Cpp/HW3/ASPS.csv",
                           "/home/reechee/Documents/Cpp/HW3/AZO.csv",
                           "/home/reechee/Documents/Cpp/HW3/CNP.csv",
                           "/home/reechee/Documents/Cpp/HW3/COST.csv",
                           "/home/reechee/Documents/Cpp/HW3/CVS.csv",
                           "/home/reechee/Documents/Cpp/HW3/DBP.csv",
                           "/home/reechee/Documents/Cpp/HW3/DGL.csv",
                           "/home/reechee/Documents/Cpp/HW3/JJP.csv",
                           "/home/reechee/Documents/Cpp/HW3/ORLY.csv",
                           "/home/reechee/Documents/Cpp/HW3/PHYS.csv"};

SAR SAR1 = SAR(); // initialize SAR object

ofstream output; // initialize output file
output.open("/home/reechee/Documents/Cpp/HW3/output.txt"); // open output file

for(auto& f : files)
{
    cout << "Now reading file: " << f << '\n';
    SAR1.parse(f);
    SAR1.initComp();
    SAR1.calcSAR();
    SAR1.printSARfile(output);
}

output.close(); // close output file
return 0;

} // end main()

void SAR::printSARfile(std::ofstream& file)
{
    file << std::setw(8) << "Date" << " ";
    file << std::setw(8) << "High" << " ";
    file << std::setw(8) << "Low" << " ";
    file << std::setw(8) << "EP" << " ";
    file << std::setw(8) << "Alpha" << " ";
    file << std::setw(8) << "Trend" << " ";
    file << std::setw(8) << "SAR"  << " " << '\n';

    for(auto const& d : data)
    {
        file <<  std::setw(8) << d.second.getDate() << "  ";
        file <<  std::setw(8) << d.second.getHigh() << "  ";
        file <<  std::setw(8) << d.second.getLow() << "  ";
        file <<  std::setw(8) << d.second.getEP() << "  ";
        file <<  std::setw(8) << d.second.getAlpha() << "  ";
        file <<  std::setw(8) << d.second.getTrend() << "  ";
        file <<  std::setw(8) << d.second.getSAR() << '\n';
    }
}

If I comment out printSARfile(output), it runs without error. With it there a seg fault is thrown. I know the calculation functions run fine as I can print everything to the console. If I try to write to the file with something like

output << "TEST";

that works fine, but only if that line is directly in main(), not if it's in one of the for loops. It's gotta be something simple I'm just ignorant to. If I drop in some output.ios::good() in there here and there, it's good to go every where between the file open and close.

Sorry for the wall-o-text. SAR::parse() included below by request.

//The function parse() uses the Boost Tokenizer library to parse the date, high,
//and low values into SARdataPoint objects.
void SAR::parse(std::string filepath)
{
typedef boost::tokenizer<boost::escaped_list_separator<char> > Tokenizer;
std::string line;

std::ifstream file(filepath);

if (file.is_open())
{
    while (getline(file, line))
    {
       Tokenizer tok(line);

        for(Tokenizer::iterator iter = tok.begin(); iter != tok.end(); ++iter)
        {
            int currentIndexInt;
            std::string currentIndexStr;

            //something in here was duplicating the final digit of the date,
            //second call to erase is a truncation work-around
            if(std::distance(tok.begin(), iter) == 0 && *iter != "Date")
            {
                currentIndexStr = *iter;
                currentIndexStr.erase(std::remove(currentIndexStr.begin(), 
                                                  currentIndexStr.end(), '-'));
                currentIndexStr.erase(currentIndexStr.size() - 1);
                currentIndexInt = std::stoi(currentIndexStr);
                this->addDataPoint(currentIndexInt);
            }

            if(std::distance(tok.begin(), iter) == 2  && *iter != "High")
            {
                this->data[currentIndexInt].setHigh(std::stod(*iter));
            }

            if(std::distance(tok.begin(), iter) == 3 && *iter != "Low")
            {
                this->data[currentIndexInt].setLow(std::stod(*iter));
            }
        }
    }
    file.close();
}
else 
{
    std::cout << "Unable to open file"; 
}
}

Here's the full git repo (sorry for the delay, never used git before).


Solution

  • I ended up finding that if I initialized the ofstream object within the for loop that iterates through the CSV files, things worked out ok. I was not able to locate the cause of the segfault, but this was a functional workaround. In doing so, however, the file was just rewritten from scratch in each iteration, so I had to eliminate the for loop entirely and just manually run the code specifically for each file, one at a time.