Question

I am trying to extract information into class objects from a colon delimited file. Each line of the file is set up in the same format. Here are the first few lines of the file:

s:Charles:Babbage:80:530213286:1133764834:mechanical engineering:3.8
e:Marissa:Meyer:37:549114177:53321:ceo:4456000
s:Alonzo:Church:92:586312110:1100539644:mathematics:4.0
e:Dana:Ulery:74:573811211:23451:engineer:124569

This is a school project and the purpose is to teach us about class inheritance. We have a base class Person and two child classes Student and Employee. We are supposed to import and store the information for students into Student objects and employee into Employee objects. I have an array of objects for each class; I'm sorting the students into the array of Student objects, same for employees, and in addition adding all people to the array of People objects.

I don't know what to do to get each piece of information with the delimiting commas. Right now I'm trying to use .getline but it doesn't seem to be working. How do I use this function (or another function) to extract information between delimiters into char arrays? Here's what I have so far for the case that the data is for an employee:

ifstream fin;
char* tempImport;
tempImport = new char[50];
int* tempIntArray;
tempIntArray = new int[10];
double tempDouble;
int tempInt;

  // get the specifier of student or employee
  fin.getline(tempImport, ':');

  if(tempImport[0]=='e'){
     // get first name
     fin.getline(tempImport, ':');
     employees[employeeIndex].setFirstName(tempImport);
     allPeople[personIndex].setFirstName(tempImport);
     // get last name
     fin.getline(tempImport, ':');
     employees[employeeIndex].setFirstName(tempImport);
     allPeople[personIndex].setFirstName(tempImport);
     // get age
     fin.getline(tempImport, ':');
     employees[employeeIndex].setAge(tempImport[0] - 0);
     allPeople[personIndex].setAge(tempImport[0] - 0);
     // get SSN
     fin.getline(tempImport, ':');
     for(int i=0;i<9;i++){
        tempIntArray[i] = tempImport[i] - 0;
        }
     employees[employeeIndex].setSsn(tempIntArray);
     allPeople[personIndex].setSsn(tempIntArray);
     // get Employee ID
     fin.getline(tempImport, ':');
     for(int i=0;i<5;i++){
        tempIntArray[i] = tempImport[i] - 0;
        }
     employees[employeeIndex].setEmpID(tempIntArray);
     // get title
     fin.getline(tempImport, ':');
     employees[employeeIndex].setTitle(tempImport);
     // get salary
     fin >> tempDouble;
     employees[employeeIndex].setSalary(tempInt);
     employeeIndex++;
     personIndex++;
     }
Was it helpful?

Solution

It looks like you're missing a parameter when you call ifstream::getline(). See: http://www.cplusplus.com/reference/istream/istream/getline/

You need the 3-parameter version of the method in order to specify a delimeter. When you call the 2-parameter version it interprets ':' as the streamsize. (Basically, ':' just resolves to the ASCII code for a colon, so that number gets passed in. What you really want for streamsize is the length of your tempImport buffer.)

However, if I may suggest (and your assignment allows it), the std::getline() version of the function may be better. (It allows you to use std::string instead of char*, which is a more C++ish way of doing things. Also you don't have to worry about if your input is bigger than your buffer.) Here's the documentation on that: http://www.cplusplus.com/reference/string/string/getline/

So basically you could do something like this:

std::string tempImport;
std::getline(fin, tempImport, ':');

As a debugging suggestion, you could print tempImport after each time you call getline() on it (regardless of which kind you use). Take those out before you submit, but those print statements could help you debug your parsing in the meantime.

std::stderr << "getline(): " << tempImport << std::endl;

Edit:

Regarding the comment below, I was able to get this to compile. (It doesn't do anything useful, but shows that std::getline() is indeed present and compiles.) Does it compile for you?

#include <fstream>

int main (int argc, char** argv)
{
        std::ifstream ifs;
        std::string str;
        std::getline(ifs, str, ':');
        return 0;
}

OTHER TIPS

If you'll pardon my saying so, you seem to have been taught one of the worst possible imitations of 'object oriented programming' (though if it's any comfort, it's also a fairly common one).

Personally, I think I'd write things quite a bit differently.

I'd probably start by eliminating all the setSalary, setTitle, etc. They're a horrible perversion of what OOP was supposed to do, losing a great deal in readability while gaining nothing in encapsulation.

Rather than providing member functions to manipulate all the members of the class, the class should provide a higher-level member to reconstitute an instance of itself from a stream.

When you do get the data, you probably do not want to create separate objects for your arrays of People/Employees/Students. Rather, each item will go into the array of either Employees or Students. Then the People will be just an array of pointers to the items in the other two arrays.

As to the details of reading the data: personally I'd probably write a ctype class that classified : as whitespace, and then just read data. For your class, you probably want to stick to using getline though.

class Person { 
    virtual std::istream &read(std::istream &is);

    friend std::istream &operator>>(std::istream &is, Person &p) { 
        return p.read(is);
    }
};

class Student : public Person { 
    std::string first_name;
    std::string last_name;
    std::string age;
    std::string ssn;
    std::string ID;
    std::string title;
    std::string salary;

    virtual std::istream &read(std::istream &is) { 
        std::getline(is, first_name, ':');
        std::getline(is, last_name, ':');
        std::getline(is, age, ':');
        // ...
        return is;
    }
};

With those in place, reading data from the file will normally be pretty simple:

std::string t;
Employee e;
Student s;

while (std::getline(infile, t, ':'))
    if (t == "e") {
        infile >> e;
        Employees.push_back(e);
    }
    else if (t =="s") {
        infile >> s;
        Students.push_back(s);
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top