1

First let me start by saying thank you to the people who post on here often, I have gained a ton of knowledge searching this site the past few years.

Okay, this question has been asked before but I have a slight twist which I can not get working.

Here is my structure.

struct person
{
    string Sex;
    string Name;
    string Match;
    int phoneNumber;
    int numInterests;
    vector<string> interests;
};

The assignment is designed as a "Dating Program" which matches people of opposite sex with similar interests.

Here is an example text file following this format:

"Sex" "Name" "Phone Number" "Number of Interests" "List of interests" "Match (if a match is found)"

M Tyler 1234567890 3 soccer football tv Jess
F Lyns 1234567890 3 hockey sex movies
F Jess 1234567890 3 soccer football tv Tyler
M Taylor 1234567890 3 hockey sex movies

In that example file, there is a match for Jess and Tyler. Here is my function thus far...

void LoadClients(std::ifstream &file,vector<person>& peps)
{
    string sex,name,interests,line, match;
    double phone,ni;
    person p;
    for(int i=0;i<maxPeople("Clients.mf"); i++){
        file>>sex>>name>>phone>>ni;
        p.Sex = sex;
        p.Name = name;
        p.phoneNumber = phone;
        p.numInterests = ni;
        for (int i=0; i<ni; i++){
            file >> line;
            p.interests.push_back(line);
        }
        file >> match;
        p.Match = match;
        peps.push_back(p);

       // person p;
        //istringstream iss( line );
    }

};

Function compiles but does not read correctly at all. Here's the rest of my work, in case you want to see it...

int maxPeople(const char* file)///Just returns the number of lines in the file
{
    ifstream inFile(file);
    int c = count(istreambuf_iterator<char>(inFile),
            istreambuf_iterator<char>(), '\n');
    return c;
}
int main()
{
    int numberOfClients=maxPeople("Clients.mf");
    ifstream file("Clients.mf");

    vector<person> peps;
    LoadClients(file,peps);

    return 0;
}

My function LoadClients was modeled after an elegant answer I found here: Reading a string and integers

All I am asking for is how to get this function to create a vector or array of people from the text file.

The final program will have additional functions "NewClient", "UnMatch", "PrintMatched", and "PrintSingles" but I think I can handle these. Any and all tips are HIGHLY welcomed :)

Thanks for reading!

EDIT1: Using this format.

void LoadClients(std::ifstream &file,vector<person>& peps)  
{  
    person p;  
    string line;  
    while( getline( file, line ) )  
    {  
        istringstream iss( line );  
        iss >> p.Sex >> p.Name >> p.phoneNumber >> p.numInterests;  
        for(int i=0;i<p.numInterests;i++){  
            string interest;  
            iss >> interest;  
            p.interests.push_back(interest);  
        }  

    }  
}; 

I decided to skip the "match" for now. I am getting a segmentation error when I access the objects from main.

ifstream file("Clients.mf");

vector<person> peps;
LoadClients(file,peps);
for(int i=0; i<numberOfClients;i++){
    cout << peps[0].Name;
}
1
  • Thank you to everyone who helped! Commented Sep 16, 2015 at 6:46

3 Answers 3

3

Because your record inputs are line-based, use a line-based reader. The problem with the program right now is it assumes there is always a match. But on the second line of the input file, there is no match. Therefore, the next space-delimited text will be read.

I like this approach to parsing lines from files because it is simple:

string line;
while( getline( file, line ) )
{
    istringstream iss( line );

    // Now, parse out of 'iss' instead of 'file'.
    person p;
    bool ok = false;
    if( iss >> p.Sex >> p.Name >> p.phoneNumber >> p.numInterests )
    {
        p.interests.reserve( p.numInterests );
        for( int i = 0; i < p.numInterests; i++ )
        {
            string interest;
            if( iss >> interest ) p.interests.emplace_back( interest );
        }

        ok = !iss.error();

        iss >> p.Match; // optional
    }

    if( ok ) peps.push_back( p );
}

You could go one step further, and define a stream input operator for your Person struct. Then, the main read loop would look like:

person p;
iss >> p;
Sign up to request clarification or add additional context in comments.

2 Comments

Using this format. void LoadClients(std::ifstream &file,vector<person>& peps) { person p; string line; while( getline( file, line ) ) { istringstream iss( line ); iss >> p.Sex >> p.Name >> p.phoneNumber >> p.numInterests; for(int i=0;i<p.numInterests;i++){ string interest; iss >> interest; p.interests.push_back(interest); } } }; I decided to skip the "match" for now. I am getting a segmentation error when I access the objects from main. cout << peps[0].Name;
In that code you put above, you never pushed the record onto your vector. Don't access index 0 unless you know the size of the vector is at least 1.
1

BTW, it's not a good idea for sex to be a string, unless you'ld like your program to handle aliens... And you may have issues with your int phoneNumbers. And numInterests is redundant if you have interests.size(). So you may do...

struct Person {
    enum class Gender {
        Unknown,
        Male,
        Female,
    };

    Gender gender;
    std::string name;
    std::string match;
    std::string phoneNumber;
    std::vector<std::string> interests;
};

Now, to the problem. The function should look like (no checking and C++11!)...

static Person::Gender readGender(std::ifstream &input) {
    char ch;
    input >> ch;
    switch(ch) {
        case 'M':
            return Person::Gender::Male;

        case 'F':
            return Person::Gender::Female;

        default:
            return Person::Gender::Unknown;
    }
}

void LoadClients(std::ifstream &file, std::vector<person> &out) {
    for(int i = 0; i < maxPeople("Clients.mf"); i++) {
        Person p;
        unsigned numInterests;

        p.gender = readGender(file);
        file >> p.name;
        file >> p.phoneNumber;
        file >> numInterests;
        for(unsigned i = 0; i < numInterests; i++){
            std::string interest;
            file >> interest;

            p.interests.push_back(interest);
        }

        file >> p.match;
        out.push_back(p);
    }
}

Edit: You should have a means for the program to differentiate whether there is a match or not, otherwise undefined frustation will seek you!

Edit: Invalidated previous comment due to comments from the OP.

Edit: Fixed some pitfalls according to comments.

3 Comments

I did leave out a key detail to the match system. The program will automatically match a two people if they have 3 or more matching interests. This is going to take me a bit to implement but it looks straight forward enough.
For any other beginners reading this, I had to add the -std=c++11 flag on the GCU GCC compiler for the above method to work. Still working on the project but thank you so far. I'll come back when its done.
I had to switch input.get() inside the switch for char g; input >> g; switch(g) get() was not "advancing" the file to the next line, rather picking up a non-visible character at the end of each line.
1

Phone and ni (I'm assuming is number of interests) shouldn't be double. I'd make Phone a string and ni an int (some would argue unsigned but close enough).

Double and Float are 'lossy' data types, not good for a count or a phone number.

You don't actually say what the behaviour is and what you expect it to be. I'm assuming that your load is going haywire, and it's because of this line:

file >> match;

You don't know whether the line has it or not, so it might pick up the first work of the next line.

I'd switch to using getLine and a string stream and check if the line is empty (IE string stream is at the end or not) before extracting match.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.