1

I am trying to write a program in C++ that emulates a college enrollment system, where the student enters their ID, and the program searches a text file for their information, and loads a struct based on the text file. I have gotten to a point where I am having trouble getting their enrolled courses into the struct's array. Using the getline function, using the ',' as the delim will also carry over the next line until the next comma. What would be the correct algorithm for this?

This is the file setup that contains fake student information:

  • 918273645,Steve,Albright,ITCS2530,MATH210,ENG140
  • 123456789,Kim,Murphy,ITCS2530,MATH101
  • 213456789,Dean,Bowers,ITCS2530,ENG140
  • 219834765,Jerry,Clark,MGMT201,MATH210

(Bullets added for layout; not in the file)

For example, the user enters "123456789" for their ID, and Kim Murphy's information is then read. Upon the first iteration of getline, "ITCS2530" is read and put into the variable, and is then loaded into the struct; no problem there. However, the last course in the list has the newline character before the next comma, so the next iteration reads "MATH101/nl213456789" and puts the entire string into the variable and tries to load that into the struct.

The first column is their ID, then their First name, last name, and then their currently-enrolled courses after that. Notice that the number of enrolled courses can vary.

Here is the code that I am currently working on:

    student login()
{
    string ID;
    student newStudent;
    string enrolled;
    int i = 0;
    while (true)
    {
        cout << "Enter Student ID: ";
        cin >> newStudent.ID;
        cout << endl;
        if (newStudent.ID.length() == 9)
            break;
        else
            cout << "That ID is invalid - IDs are 9 digits" << endl;
    }
    ifstream inFile;
    ofstream outFile;
    inFile.open("registration.txt");
    if (inFile.is_open())                                                               
    //Check if file is open
    {
        while (!inFile.eof())                                                           
        //While not at end of file
        {
            getline(inFile, ID, ',');                                                   
            //Search for ID
            if (ID == newStudent.ID)
            {
                getline(inFile, newStudent.fName, ',');                                         
                //Assign fName and lName
                getline(inFile, newStudent.lName, ','); 

                while (enrolled != "\n")
                {
                    getline(inFile, enrolled, ',');
                    if (enrolled == "\n")
                    {
                        cout << "Not currently enrolled in a class." << endl;
                    }
                    else
                    {
                        newStudent.courses[i] = enrolled;
                        i++;
                    }
                }
                    cout << newStudent.lName << ", Welcome to the MCC Enrollment System!" << endl;
                for (i = 0; i <= NUM_OF_COURSES; i++)
                {
                    cout << "Enrolled courses: " << newStudent.courses[i] << endl;
                }

                    cout << endl;
                    break;
                    //Stops searching
            }
            else                                                                        
                //Ignores rest of line - used to skip to the next line
            {
                getline(inFile, ID, '\n');
            }
            if (inFile.eof())                                                           
                //If ID was not found
            {
                inFile.close();
                cout << "Enter First Name: ";                                           
                //Begin entry of new student
                cin >> newStudent.fName;
                cout << endl;
                cout << "Enter Last Name: ";
                cin >> newStudent.lName;

                cout << endl;
                outFile.open("registration.txt", ios::app);
                if (outFile.is_open())
                {
                    outFile << newStudent.ID << "," << newStudent.fName << "," << newStudent.lName << "\n";
                }
            }
        }
    }
    return newStudent;
}

Thanks in advance for any help.

Chris
  • 191
  • 2
  • 12
  • can you show the code that you have? – default Apr 25 '16 at 20:33
  • We need to see how you get the data out of the file. The reason we need to see that is fgets, fscanf, std::cin and std::getline all get data separated either by newlines or by whitespace. – Jerry Jeremiah Apr 25 '16 at 20:47
  • @JerryJeremiah I have updated the question with a snippet of the code I am working on. – Chris Apr 25 '16 at 20:54
  • std::getline only reads up to the newline - it can't read "MATH101/nl213456789" You are doing something else to clobber the string. Can you show us all the code that reads from the file and loads the struct? – Jerry Jeremiah Apr 25 '16 at 21:06
  • @JerryJeremiah I updated the question with the full function – Chris Apr 25 '16 at 21:16
  • I see. That is a problem. You are using comma as the delimiter and so newline is not a valid delimiter and so it is read as part of the text. I think the answer is to call istream::getline with the default delimiter (newline) and then use a stringstream as an input stream so you can call getline with the comma delimiter on the string you already read. I will try to make an example so I can write an answer. – Jerry Jeremiah Apr 25 '16 at 21:35
  • @JerryJeremiah That would help a lot. I really do appreciate this – Chris Apr 25 '16 at 21:43

2 Answers2

4

The problem is that std::getline takes exactly one character as a delimiter. It defaults to a newline but if you use another character then newline is NOT a delimiter any more and so you end up with newlines in your text.

The answer is to read the entire line into a string using std::getline with the default (newline) delimiter and then use a string stream to hold that line of text so you can call std::getline with a comma as a delimiter.

Something like this:

#include <fstream>
#include <sstream>
#include <iostream>
#include <vector>

int main()
{
    std::ifstream inFile("registration.txt");
    if (inFile.is_open())
    {
        std::string line;
        while( std::getline(inFile,line) )
        {
            std::stringstream ss(line);

            std::string ID, fname, lname;
            std::getline(ss,ID,',');    std::cout<<"\""<<ID<<"\"";
            std::getline(ss,fname,','); std::cout<<", \""<<fname<<"\"";
            std::getline(ss,lname,','); std::cout<<", \""<<lname<<"\"";

            std::vector<std::string> enrolled;
            std::string course;
            while( std::getline(ss,course,',') )
            {
                 enrolled.push_back(course); std::cout<<", \""<<course<<"\"";
            }
            std::cout<<"\n";
        }
    }
    return 0;
}

In this example I am writing the text to the screen surrounded by quotes so you can see what is read.

Jerry Jeremiah
  • 9,045
  • 2
  • 23
  • 32
-1
split(string, seperator)

split("918273645,Steve,Albright,ITCS2530,MATH210,ENG140", ",")
split("123456789,Kim,Murphy,ITCS2530,MATH101", ",")
split("213456789,Dean,Bowers,ITCS2530,ENG140", ",")
split("219834765,Jerry,Clark,MGMT201,MATH210", ",")

I know very little C++, but I remember this command.

Anuga
  • 2,619
  • 1
  • 18
  • 27