0

I have to read in values separated by ";" from a csv file...types are int;char[];char[];char[],float e.g: I have to assemble them in a new struct type and then insert them into a struct array of that type... SAMPLE FILE:

2345678;Meier;Hans;12.10.1985;2.4;      
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.1;
7584932;Bau;Maschine;02.02.2010;2.3;
2345678;Meier;Hans;12.10.1985;2.4;      
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.2;
7584932;Bau;Maschine;02.02.2010;2.3;
2345678;Meier;Hans;12.10.1985;2.4;      
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.1;
7584932;Bau;Maschine;02.02.2010;2.3;
2345678;Meier;Hans;12.10.1985;2.4;      
1234567;Müller;Fritz;17.05.1990;1.9;
8392019;Thomas;Kretschmer;28.3.1920;2.5;
3471144;Mensch;Arbeit;29.2.2013;4.5;
2039482;Test;Test;30.20.2031;2.0;
7584932;doof;doof;02.02.2010;2.3;
2039482;Test;Test;30.20.2031;2.0;
7584932;doof;doof;02.02.2010;2.3;
2039482;Test;Test;30.20.2031;2.0;
7584932;doof;doof;02.02.2010;2.3;  

I wrote some code, it all worked fine and output is shown correctly, however the last line from the file is not parsed correctly, it shows me some rubbish, here is my Code:

#include <cstdlib>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>

using namespace std;

int main(int argc, char **argv)
{
    struct Stud{
        long matrnr;
        char vorname[30];
        char name[30];
        char datum[30];
        float note;
    };

    const int MAX = 30;
    Stud stud;  
    Stud mystud[30]; // <<-- Array of "Stud" type
    //memset((void*)mystud,0,sizeof(mystud) * sizeof(Stud));
    int wordCounter(0);
    int i(0); //thats the charCounter or index
    int studentCounter(0);
    char wort[MAX];
    //int matrnr;
    //char vorname[MAX];
    //char name[MAX];
    //char datum[MAX];
    //float note;


  FILE * pFile;
  int cnr(0); 


  pFile=fopen("studentendaten.txt","r");  
  if (pFile==nullptr) 
  {
      perror ("Fehler beim öffnen der Datei");
  }

  else
  {       
    while (cnr != EOF) 
    {       
        (cnr=fgetc(pFile)) ;


        if ((char)cnr == '\n') {
            mystud[studentCounter] = stud;
            studentCounter++;                       
            continue;           
        }

        if ((char)cnr == ';') { 

            wort[i] = '\0'; 

            switch (wordCounter % 5) {

                case 0:             
                stud.matrnr = atol(wort);
                break;

                case 1:
                strcpy(stud.name, wort);
                break;

                case 2:
                strcpy(stud.vorname, wort);
                break;

                case 3:
                strcpy(stud.datum,wort);
                break;

                case 4:
                stud.note = atof(wort); 
                break;
            }       

            wordCounter++;          
            i = 0;
            continue;
        }

        if (wordCounter %  5 == 0 && (char)cnr != ';') {        
        wort[i] = (char)cnr;
        i++;
        //stud.matrnr = atol(wort);
        }           

        if (wordCounter % 5 == 1) {
            wort[i] =  (char)cnr;
            i++;
        //strcpy(stud.name, wort);
        }

        if (wordCounter % 5 == 2) {
            wort[i] = (char)cnr;
            i++;
            //strcpy(stud.vorname, wort);
        }

        if (wordCounter % 5 == 3) {
            wort[i] = (char)cnr;
            i++;
            //strcpy(stud.datum,wort);
        }

        if (wordCounter % 5 == 4) {
            wort[i] = (char)cnr;
            i++;
            //stud.note = atof(wort);                       
        }

    }           

    fclose (pFile);
}
for (int i(0) ; i <= studentCounter; i++) {
cout <<mystud[i].matrnr << "    " << mystud[i].name << "    " << mystud[i].vorname <<"    " 
<< mystud[i].datum <<"    " << mystud[i].note << endl;
  //printf("%5ld        %5s      %5s     %5s     %5f     \n",mystud[i].matrnr,mystud[i].name,mystud[i].vorname,mystud[i].datum,mystud[i].note);

}

    return 0;
}

only when I put

mystud[studentCounter] = stud;
    fclose (pFile);
}

it reads in the last line.. it should do it in the code above already, but I can't find the error...

moreover, I have to separate my program in different parts... different header classes and a main class where it comes all together... any suggestions how I should separate my program ?

MMMM
  • 3,320
  • 8
  • 43
  • 80
  • My tip is that you get a full line (with [`fgets`](http://en.cppreference.com/w/c/io/fgets)) and use [`strtok`](http://en.cppreference.com/w/c/string/byte/strtok) to split the lines. Then use [`strtol`](http://en.cppreference.com/w/c/string/byte/strtol) or [`strtod`](http://en.cppreference.com/w/c/string/byte/strtod) to parse the numbers. – Some programmer dude Nov 05 '13 at 14:09
  • 1
    You should probably try to compile a **much** smaller code snippet for your issue. – Grimm The Opiner Nov 05 '13 at 14:12
  • Check this code, and extend it to read the columns into your data members. http://stackoverflow.com/questions/1120140/csv-parser-in-c – Damian Nov 05 '13 at 14:27
  • The last line of the file may not end with a newline. The series of 5 if()s at the end of the while all do the same thing, so you just need one copy of the if() body. – brian beuning Nov 05 '13 at 14:27
  • Is there a specific reason you are using `FILE` vs. `std::fstream`? – crashmstr Nov 05 '13 at 14:29

1 Answers1

3

In my opinion, you should start by making up your mind whether you're trying to do this in C, or C++. You've tagged it as C++, but although it has a few things that look vaguely C++ish, the code strikes me as a lot more C than C++ overall.

If I were doing this in C++, I'd start by writing a small ctype facet that classified semicolons as white-space:

struct field_reader: std::ctype<char> {

    field_reader(): std::ctype<char>(get_table()) {}

    static std::ctype_base::mask const* get_table() {
        static std::vector<std::ctype_base::mask> 
            rc(table_size, std::ctype_base::mask());

        rc[';'] = std::ctype_base::space;
        return &rc[0];
    }
};

With that in place, reading the data itself becomes trivial:

struct Stud{
    long matrnr;
    std::string vorname;
    std::string name;
    std::string datum;
    float note;

    friend std::istream &operator>>(std::istream &is, Stud &s) { 
        return is >> s.matrnr >> s.vorname >> s.name >> s.datum >> s.note;
    }

    // we'll also add an operator<< to support printing these out:
    friend std::ostream &operator<<(std::ostream &os, Stud const &s) { 
        return os << s.matrnr  << "\t"
                  << s.vorname << "\t"
                  << s.name    << "\t"
                  >> s.datum   << "\t"
                  << s.note;
    }
};

Rather than using an array, we really want to use a std::vector to hold those, and we can use a pair of std::istream_iterators to read the data from the file into the vector:

// Open the file:
std::ifstream in("studentendaten.txt");

// Use the ctype facet we defined above to classify `;` as white-space:
in.imbue(std::locale(std::locale(), new field_reader);

// read all the data into the vector:
std::vector<Stud> studs{std::istream_iterator<Stud>(in),
                        std::istream_iterator<Stud>()};

// show what we read:
for (auto s : studs) 
    std::cout << s << "\n";
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • That's a nice solution but wouldn't it be far simpler to just use a stringstream tokenizer? – Ben J Nov 05 '13 at 14:56
  • @BenJ: Yes and no. If you only ever did something like this once, yes a stringstream with (for example) `std::getline(whatever, ';')` would probably be a tiny bit simpler (but not much). By the second or third time you do nearly the same thing, this style becomes a lot simpler (at least in my experience). – Jerry Coffin Nov 05 '13 at 15:15