0

Sorry if anything I ask is obvious or stupid, I'm about 2 weeks into learning C++.

EDIT: I found the problem, it's that in the output from the file, all spaces are changed to a different character. Could someone close this question?

I've been trying to write a program that collects data about hypothetical employees. Recently, I have tried to let it read from a file - however, every time I run the code below (running fix();) I get a segmentation fault. Using the breakpoints, I narrowed it down to std::ifstream file(filename). I have tested it and tested it, and have figured out that the filename variable is not the issue - it still throws a fault even if I use a string literal. Other things I've found:

-Separating the std::ifstream file(filename) and placing it into another file where it cannot reference any of this file's variables works fine.

-The segmentation fault does NOT occur when I enter the name of a file that DOES NOT exist - instead, it gets to breakpoint 0 (like it should), prints Error in opening file. (like it should), and returns false (like it should).

Does anyone know why this is happening and how to fix it? This has been bothering me for days.

(Also, I am using Ubuntu 14.04 with G++ 4.8 - launch flag -std=c++1y)

EDIT Ok, this is getting extremely weird. The first thing I did was debug my program using std::couts every other line. This pinpointed the problem to std::ifstream. However, under @M.M and @hyde 's reccomendation, I ran my program through the Code::Blocks debugger. It told me that the segmentation fault occurred at emp->firstName = lineList[2]. So I commented out that line - but the debugger still says that line is the problem! It's saying that the problem is a COMMENTED OUT LINE! I'm more confused than ever.

#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <iostream>
#include "baselibrary.h"
struct Employee
{
    int16_t id; // Employee ID
    std::string lastName; // Employee's last name
    std::string firstName; // Employee's first name
    char middleInitial; // Employee's middle initial
    int16_t age;
    bool gender; // false is male, true is female
    float salary;
    int16_t experience; // # of years working at company
    int16_t department; // Department from Departments::
};
std::vector<Employee> employeeArrayN;
int empNumN{1};
//... tons of snipped out code ...//
bool loadFromDatabaseFileN(){
    std::string filename;
    std::cout << "Please enter filename to load (with extension): ";
    std::getline(std::cin, filename);
    std::ifstream file(filename);
    std::cout << "Breakpoint 0!";
    if (!file){
        std::cout << "Error in opening file. ";
        return false;
    }
    std::cout << "Breakpoint 1!";
    while (file) // ifstream returns 0 when reaching EOF - 0 is boolean false
    {
        // it's probably OK to ignore the code under here, but you never know...
        std::string lineInput;
        std::cout << "Breakpoint 2!";
        Employee *emp = new Employee;
        std::cout << "Breakpoint 3!";
        ++empNumN;
        std::cout << "Breakpoint 4!";
        std::getline(file, lineInput);
        std::vector<std::string> lineList = splitString(lineInput, ' ');
        int16_t tempId;
        std::cout << "Breakpoint 5!";
        std::stringstream(lineList[0]) >> tempId;
        emp->id = tempId;
        emp->lastName = lineList[1];
        emp->firstName = lineList[2];
        char tempMInit;
        std::stringstream(lineList[3]) >> tempMInit;
        emp->middleInitial = tempMInit;
        int16_t tempAge;
        std::stringstream(lineList[4]) >> tempAge;
        emp->age = tempAge;
        bool tempGend;
        std::stringstream(lineList[5]) >> tempGend;
        emp->gender =  tempGend;
        float tempSalary;
        std::stringstream(lineList[6]) >> tempSalary;
        emp->salary = tempSalary;
        int16_t tempExperience;
        std::stringstream(lineList[7]) >> tempExperience;
        emp->experience = tempExperience;
        int16_t tempDepartment;
        std::stringstream(lineList[8]) >> tempDepartment;
        emp->department = tempDepartment;
        employeeArrayN.resize(empNumN);
        employeeArrayN[empNumN - 1] = *emp;
        std::cout << "Added new employe: [ID " << emp->id << "] " << emp->lastName << ", " << emp->firstName << " " << emp->middleInitial << ". \n";
    }
    file.close();
    return true;
}
//...snip...//

//fix is a function I added just for this question, I wouldn't want to bother you with my monolithic actual function//
void fix()
{
    bool notGonnaUse = loadFromDatabaseFileN();
}
  • Your code has several possible sources of undefined behaviour. For example, perhaps `lineList[8]` is out of bounds of the vector, or perhaps any of the `>>` fail, leaving an indeterminate value which you then read. Try [debugging your code](http://ericlippert.com/2014/03/05/how-to-debug-small-programs/). If you want someone else to debug it for you then you need to provide a [MCVE](http://stackoverflow.com/help/mcve) along with the exact input file you provided which gave the problem, so that someone else can reproduce your results. – M.M Mar 24 '16 at 05:15
  • You leak memory (there is no `delete` corresponding to `new Employee`), but that is probably unrelated to the segfault – M.M Mar 24 '16 at 05:16
  • You aren't showing the input file... Also, to see where segmentation fault happens, please use debugger to examine the call stack. `std::ifstream file(filename)` is very very unlikely to crash, unless you first have memory corruption. For example, check that `lineList` really has 9 elements, before proceeding to access index 8... – hyde Mar 24 '16 at 05:25
  • Also, look up `std::vector::push_back` method, and use it instead of your current method of using `resize`. – hyde Mar 24 '16 at 05:38
  • @M.M This is getting very weird. I already ran debugging on my program, and the debugger gave me a SIGSEGV on ifstream. Now, however, after adding code, the debugger gives me a SIGSEGV on emp->firstName = lineList[2]. Now, normally, I would debug this part, but the problem here is that that line is after 4 cout breakpoints, all of which should have printed, but didn't. –  Mar 24 '16 at 16:52
  • If you didn't also output a newline and `flush`, you may not see the output when breakpoint is hit. You could try replacing `lineList[n]` with `linelist.at(n)`, then you will get an exception instead of undefined behaviour. Alternatively, check `lineLine.size() >= 8` before embarking on that series. The error on commented-out line could be explained by not actually rebuilding the code before running the changed version. The most productive approach is probably still to create a MCVE. – M.M Mar 24 '16 at 23:26

1 Answers1

0

This may not fix your problem but...

Using

while ( file )
{
   ...
   std::getline(file, lineInput);
   ...
}

is a problem. See Why is iostream::eof inside a loop condition considered wrong?.

Using

while ( file ) { }

suffers from the same problems as using:

while ( !file.eof() ) { }

Change that code to use:

// Move the declaration of lineInput out of the loop.
std::string lineInput;
while ( std::getline(file, lineInput) )
{
   ...
}
Community
  • 1
  • 1
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • note: even if this fixes the problem, it would be good to continue to debug the original crash -- a program should not be able to crash just by being given some particular input file, this leads to security vulnerabilities. – M.M Mar 24 '16 at 05:17
  • Thanks, but this still doesn't fix my problem. –  Mar 24 '16 at 16:38
  • @PracticalProblems, I can't see any other problem in your code. You may want to try the divide and conquer approach. – R Sahu Mar 24 '16 at 16:49