-2

I'm sing C++ to build a csv processor for study purposes and having some throuble with segmentation faults. This processor will have one main class (csvcontroller) that should be the instance of the current file. This class controls two structures. One of them (CsvLine) is a list of all file lines and the other one (CsvColumn) represents a list of all columns on each list. My segmentation fault happens when i try to write the column value into the struct but it only happens when i'm using strings. If we replace string for int, the processor runs the way i want.

This is my code:

csvcontroller.h:

#ifndef CSVCONTROLLER_H
#define CSVCONTROLLER_H

#include <iostream>
#include <string>
using namespace std;


typedef struct CsvLine{

    struct CsvLine* next = NULL;
    struct CsvColumn* first = NULL;
    struct CsvColumn* last = NULL;
    struct CsvLine* previous = NULL;

};

typedef struct CsvColumn{

    struct CsvColumn* previous = NULL;
    string value = NULL;
    struct CsvColumn* next = NULL;

};


class csvcontroller{
    public:
        bool loadfile(string file_location,char separator);
        bool savefile(string file_location,char separator);
        CsvLine* getFirst();
        CsvLine* getLast();
        CsvLine* addLine();
        void addColumn(CsvLine* line,string* value);
        int getCount();
    protected:
        string path;
        CsvLine* first = NULL;
        CsvLine* last = NULL;
        int line_count;
    private:
};

#endif // CSVCONTROLLER_H

csvcontroller.cpp

#include "csvcontroller.h"
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <sstream>

using namespace std;

bool csvcontroller::loadfile(string file_location,char separator){

    this->path = file_location;
    const char * path = this->path.c_str();

    //Initializing read stream
    ifstream file;
    file.open(path);

    //Reading our file
    while(!file.eof()){

        string line;
        std::getline(file,line);
        stringstream stream(line);

        if(!line.empty()){

            string col;
            CsvLine* ln = this->addLine();

            while(std::getline(stream,col,separator)){
                this->addColumn(ln,&col);
            }

        }//if(!line.empty

    }//while(!file.eof())



    return false;
}

CsvLine* csvcontroller::addLine(){
    CsvLine* item = (CsvLine*) malloc(sizeof(CsvLine));

    if(this->first == NULL){

        this->first = item;
        this->last = item;

    }else{

        this->last->next = item;
        item->previous = this->last;
        this->last = item;

    }
}

void csvcontroller::addColumn(CsvLine* line,string* value){

    CsvColumn* col = (CsvColumn*) malloc(sizeof(CsvColumn));
    col->value = value;//Here's the problem

    if(line->first == NULL){

        line->first = col;
        line->last = col;

    }else{

        line->last->next = col;
        col->previous = line->last;
        line->last = col;

    }

}

/*
 *  GET & SET
 */

CsvLine* csvcontroller::getFirst(){
    return this->first;
}

CsvLine* csvcontroller::getLast(){
    return this->last;
}

main.cpp:

#include <iostream>
#include <csvcontroller.h>

using namespace std;

int main(){

    csvcontroller lista_logradouros;
    lista_logradouros.loadfile("C:\\Users\\d786282\\Desktop\\Base_JUN_V2\\20140828_base_jun_padronizada.csv",';');
    CsvLine* aux = lista_logradouros.getFirst();
    do{
        aux = aux->next;
    }while(aux != NULL);


}

How can i debug / solve this?

dan_soah
  • 18
  • 1
  • 5
  • 2
    http://en.cppreference.com/w/cpp/string/basic_string/basic_string – chris Aug 29 '14 at 19:20
  • Compile with all warnings and debug info (`g++ -Wall -g`). Use a debugger (`gdb`) and a memory leak detector ([valgrind](http://valgrind.org/)...). – Basile Starynkevitch Aug 29 '14 at 19:21
  • _"How can i debug / solve this?"_ You can use a decent debugger like GDB (depends on your actual tool chain), to step through your program instruction line wise, or use [_caveman debugging_](http://stackoverflow.com/questions/186237/program-only-crashes-as-release-build-how-to-debug) to catch up. – πάντα ῥεῖ Aug 29 '14 at 19:25
  • 4
    The root of the problem is this: You need to learn C++. You need a decent book and try to forget or at least question a few of your C habits, because your code mixes a few C++ features into code that is at its core C, and that won't work. For example, allocation is one thing that is different because it has to take construction into account. It continues with not using raw pointers, or preferably no pointers at all, dropping unnecessary typedefs for structs, using standard containers instead of self-rolled linked lists, exceptions instead of returnvalues, C++ casts (when not avoidable). – Ulrich Eckhardt Aug 29 '14 at 19:36
  • I had like two seconds, so sorry, but what I was getting at was that you can't initialize a string with `NULL`. There are other problems, such as using `eof()` incorrectly. You have no guarantee `line` will just be an empty line as opposed to a failed read. – chris Aug 29 '14 at 20:21
  • True, the misuse of eof() is another issue. Failure to open the file is also one, it will result in an endless loop, too, because it will never reach eof(). – Ulrich Eckhardt Aug 30 '14 at 10:21

1 Answers1

1

In your header, 'csvcontroller.h', it appears that you have defined the CsvColumn class like this:

typedef struct CsvColumn{

    struct CsvColumn* previous = NULL;
    string value = NULL;
    struct CsvColumn* next = NULL;

};

But you're assigning to is thusly:

void csvcontroller::addColumn(CsvLine* line,string* value){

    CsvColumn* col = (CsvColumn*) malloc(sizeof(CsvColumn));
    col->value = value;

You're trying to turn a pointer-to-std::string into a std::string by the assignment operator. You could either deref your pointer to make the operation a copy:

col->value = *value;

Or you could change your code to take the string by-ref, rather than by-pointer (this is what I'd suggest):

void csvcontroller::addColumn(CsvLine* line,const string& value){

    CsvColumn* col = (CsvColumn*) malloc(sizeof(CsvColumn));
    col->value = value;

Obviously it depends on your requirements for your application.

Cheers!

benschumacher
  • 162
  • 2
  • 11
  • 2
    You have captured the problem, but using malloc() to allocate storage for an object (and without constructing it) isn't a suitable solution. – Ulrich Eckhardt Aug 29 '14 at 19:31
  • A reasonable point, but Danilo asked why it was segfault'ng. I choose to without my opinions re: code structure in favor of addressing the specific ask. In my experience, trying to find "pure" C++ is a bit like trying to find the Heffalump. – benschumacher Aug 29 '14 at 20:06
  • Reduce your problems, use `std::vector` and `std::list`. – Thomas Matthews Aug 29 '14 at 20:55
  • CsvColumn is supposed to contain a string object. Passing NULL (should be nullptr, I believe) to the ctor is the first problem. Well, it would be the first problem if you even called the ctor. Instead, when assigning, the string releases its former content, which is at that time random garbage and which it will happily pass to free() for deallocation. No, sorry, there's too many problems with Danilo's code and fixing just one is not enough. – Ulrich Eckhardt Aug 30 '14 at 10:20