Thread: Split function problem

  1. #1
    Registered User
    Join Date
    Aug 2013
    Posts
    33

    Split function problem

    I'm working on an address database. The assignment is to append and display records in said database. The records are to be written to file in CSV format and then read from the file using a split function to separate the file string into separate fields (name, address, city, and so on). The professor provided a basic code with comments to start this particular assignment and I think I've got a near workable solution, but I'm running into a couple of issues.

    1) The writeData function isn't looping. Regardless of the answer provided (Y or N), it simply exits the program.

    2) I'm not really sure that I understand the split function. I understand what it is supposed to do and the code that the professor has provided compiles as is, so I'm not really sure what I need to be changing around. The file output that he is looking for should look similar to this:

    Show Records
    __________________________________________
    Record #1
    Name...........John Smith
    Street..........902 Union Ave
    City.............Any Town
    State...........TX
    Zip Code......78552
    __________________________________________
    Record #2
    Name...........Eric Jones
    Street..........345 State Way
    City.............Fresno
    State...........CA
    Zip Code.......93432

    I haven't really changed much of this function (mainly just included the comma ',' as the delimiter) and the comments written in the function are the professor's. I'm not sure if I'm just trying to make this more complex than it needs to be or what. And since the writeData isn't working, then I'm not sure if the split function will work either.

    Anyone have any thoughts?
    Thanks.

    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    void menu(void);
    void writeData(void);
    void readData(void);
    string * split(string theLine, char);
    
    const char FileName[] = "TestAddress.txt";
    int main () 
    {
        menu();
        return 0;
    } //end main
    
    void menu(void) //allow user to choose to append records, display records or exit the program
    {
        cout << "Do you wish to (A)ppend records, (D)isplay records, or (E)xit" << endl;
        char answer;
        cin >> answer;
        
        switch (answer)
        {    
        case 'A':; case 'a':;
                writeData(); 
                break;
        case'D': case 'd':;
                readData();
                break;
        case'E': case 'e':;
                cout << "Thank you for using our program." << endl;
                break;
            default:
                cout << "Invaild selection" << endl;
        }
    }
    
    
    void writeData(void)//Write the Address Info to a file
    {
        bool another = true;
        fstream addInfo;
            addInfo.open("TestAddress.txt", ios::out|ios::app);
    
        do
        {
            cout << endl;
            cout << "First and Last Name : " << endl;
            string name;
            getline(cin, name, '\n');
            cin >> name;
    
            cout << endl;
            cout << "Street Address: " << endl;
            string address;
            getline(cin, address, '\n');
            cin >> address;
    
            cout << endl;
            cout << "City: " << endl;
            string city;
            getline(cin, city, '\n');
            cin >> city;
    
            cout << endl;
            cout << "State: " << endl;
            string state;
            getline(cin, state, '\n');
            cin >> state;
    
            cout << endl;
            cout << "Zip Code: " << endl;
            string zip;
            getline(cin, zip, '\n');
            cin >> zip;
    
            addInfo << name << "," << address << "," << city << "," << state << "," << zip << endl;
    
            cout << endl;
            cout << "Enter Another Record? (Y/N)" << endl;
            int answer;
            cin >> answer;
                if ((answer = 'N') || (answer = 'n'))
                    another = false;
                else
                    another = true;
        }
        while (another);
        
    
    addInfo.close();
    }
    
    void readData(void)
    {
        string name, address, city, state, zip;
        fstream addInfo;
        addInfo.open("TestAddress.txt", ios::in);
            while(!addInfo.eof())
            {
                addInfo >> name >> address >> city >> state >> zip;
                string*split(string theLine, char); //use split function to break up to string into separate
            }
        addInfo.close();
    }
    
    string * split(string theLine, char)
    {
            //Break theline into fields and save the fields to an array.
            //Each field will occupy one element in a character array.
            //theLine is a string with fields separated with theDeliminator character.
            //Assumes the last field in the string is terminated with a newline.
            //Useage: string *theFields = split(lineBuffer, ',');
    
            //determine how many splits there will be so we can size our array
            int splitCount = 0;
            for(int i = 0; i < theLine.size(); i++)
            {
                if (theLine[i] == ',')
                splitCount++;
            }
            splitCount++; //add one more to the count because there is not an ending comma 
    
            
            string* theFieldArray;//create an array to hold the fields
            theFieldArray = new string[splitCount]; //split the string into seperate fields
            string theField = "";
            int commaCount = 0;
    
            for(int i = 0; i < theLine.size(); i++) //read each character and look for the deliminator
            { 
                if (theLine[i] != ',') 
                {
                    theField += theLine[i]; //build the field
                }
                else 
                    { //the deliminator was hit so save to the field to the array
                        theFieldArray[commaCount] = theField; //save the field to the array
                        theField = "";
                        commaCount++;
                    }
            }
            theFieldArray[commaCount] = theField; //the last field is not marked with a comma...
    
            return theFieldArray;
    } //end split

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    You would benefit from reading following articles
    FAQ > Flush the input buffer - Cprogramming.com
    FAQ > Why it's bad to use feof() to control a loop - Cprogramming.com

    Second is for C - but same principals could be used in C++
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quick suggestions:
    - Don't use new[]. Use vectors.
    - Don't use char arrays. Use std::string.
    - Use existing algorithms. See Algorithms library - cppreference.com.
    - Use constructors. ifstream has a constructor that opens a file. No need to call open.
    - Don't call close. This is done automatically by the destructor.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #4
    Registered User
    Join Date
    Jul 2013
    Posts
    158
    Quote Originally Posted by Elysia View Post
    Quick suggestions:
    - Don't use new[]. Use vectors.

    You seems REALLY fond of Vectors..But i too now

  5. #5
    11DE784A SirPrattlepod's Avatar
    Join Date
    Aug 2013
    Posts
    485
    Quote Originally Posted by Elysia View Post
    Quick suggestions:
    - Don't use new[]. Use vectors.
    - Don't use char arrays. Use std::string.
    - Use existing algorithms. See Algorithms library - cppreference.com.
    - Use constructors. ifstream has a constructor that opens a file. No need to call open.
    - Don't call close. This is done automatically by the destructor.
    This is very good advice, but a lot of school/uni assignments require you not to use these things. Just saying.

    I tried to say this the other day but didn't express myself well and got in trouble.

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by SirPrattlepod View Post
    This is very good advice, but a lot of school/uni assignments require you not to use these things. Just saying.

    I tried to say this the other day but didn't express myself well and got in trouble.
    I know, but it doesn't harm to mention them.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User
    Join Date
    Aug 2013
    Posts
    33
    Quote Originally Posted by Elysia View Post
    I know, but it doesn't harm to mention them.
    Yeah, I'm afraid we haven't touched on vectors as yet and at the moment, I'm not even concerning myself with the split function anymore since I can't get the writeData and readData functions to work. Updated code posted below.

    writeData
    For some reason, when writing data, the program has stopped going beyond the first entry...in other words, I can enter "name" and that's it. It doesn't prompt for anything else. I'm not sure what I did to it because that part was working fine earlier. The other problem I'm having with writeData is still in the loop. Instead of looping back around with a "Y" answer, it simply calls back up the menu function the way an "N" answer is supposed to do.

    readData
    Something is right with this one and I'm not sure what. It compiles but I get debugging errors regarding file access and after that the program simply breaks.

    Any thoughts??

    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    void menu(void);
    void writeData(void);
    void readData(void);
    string * split(string firstLine, char);
    
    const char FileName[] = "c:\TestAddress.txt";
    int main () 
    {
        menu();
        return 0;
    } 
    
    void menu(void)
    {
        char answer;
    
        do
        {
        cout << "Welcome to the Address Database." << endl;
        cout << "Do you wish to (A)ppend records, (D)isplay records, or (E)xit the program?" << endl;
        cin >> answer;
        cin.ignore();
        
            switch (answer)
            {    
                case 'A':; case 'a':;
                writeData(); 
                break;
                case'D': case 'd':;
                readData();
                break;
                case'E': case 'e':;
                cout << "Thank you for using our program." << endl;
                break;
                default:
                cout << "Invaild selection" << endl;
            }
        }
        while ((answer != 'E') || (answer != 'e'));
    }
    
    
    void writeData(void)
    {
        char answer;
        
        fstream outAddInfo;
            outAddInfo.open("c:\TestAddress.txt", ios::out|ios::app);
    
        do
        {
            cout << endl;
            cout << "First and Last Name : " << endl;
            string name;
            getline(cin, name, '\n');
            cin >> name;
    
            cout << endl;
            cout << "Street Address: " << endl;
            string address;
            getline(cin, address, '\n');
            cin >> address;
    
            cout << endl;
            cout << "City: " << endl;
            string city;
            getline(cin, city, '\n');
            cin >> city;
    
            cout << endl;
            cout << "State: " << endl;
            string state;
            getline(cin, state, '\n');
            cin >> state;
    
            cout << endl;
            cout << "Zip Code: " << endl;
            string zip;
            getline(cin, zip, '\n');
            cin >> zip;
    
            outAddInfo << name << "," << address << "," << city << "," << state << "," << zip << endl;
    
            cout << endl;
            cout << "Enter Another Record? (Y/N)" << endl;
            cin >> answer;
            if (answer = 'N' || (answer = 'n'))
            {
                menu();
            } 
            
        }
        while (answer = 'Y' || (answer = 'y'));
        
    
    outAddInfo.close();
    }
    
    void readData(void)
    {
        string name, address, city, state, zip;
        fstream inAddInfo;
        string firstLine;
        inAddInfo.open("c:\TestAddress.txt", ios::in);
        if (inAddInfo.is_open())
            inAddInfo >> firstLine;
            while(!inAddInfo.eof())
            {
                getline(inAddInfo, firstLine, '\n');
                string*theFields = split(firstLine, ',');
                cout << "Name............ " << theFields[0] << endl;
                cout << "Street Address.. " << theFields[1] << endl;
                cout << "City............ " << theFields[2] << endl;
                cout << "State........... " << theFields[3] << endl;
                cout << "Zip Code........ " << theFields[4] << endl;
            }
        inAddInfo.close();
    }
    
    string * split(string firstLine, char)
    {
            int splitCount = 0;
            for(int i = 0; i < firstLine.size(); i++)
            {
                if (firstLine[i] == ',')
                splitCount++;
            }
            splitCount++;  
    
            string* theFieldArray;
            theFieldArray = new string[splitCount]; 
            string theField = "";
            int commaCount = 0;
    
            for(int i = 0; i < firstLine.size(); i++) 
            { 
                if (firstLine[i] != ',') 
                {
                    theField += firstLine[i]; 
                }
                else 
                    { 
                        theFieldArray[commaCount] = theField; 
                        theField = "";
                        commaCount++;
                    }
            }
            theFieldArray[commaCount] = theField; 
    
            return theFieldArray;
    }

  8. #8
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    '\' is escape character, you need '\\' in C-strings

    Code:
    getline(cin, address, '\n');
            cin >> address;
    So which way it is? using getline or using >>?

    Do not use eof to control loop - read FAQ
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  9. #9
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by worl4125 View Post
    Yeah, I'm afraid we haven't touched on vectors as yet and at the moment, I'm not even concerning myself with the split function anymore since I can't get the writeData and readData functions to work.
    It is well worth spending the time to learn about them. You can simplify your split function a lot by doing it.
    Don't be afraid to touch what you haven't covered. It simply means that your instructor is either a) stuck in the past or b) has his/her priorities mixed up. You should almost never use new to reallocate arrays the way you do here in real code.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  10. #10
    Registered User
    Join Date
    Aug 2005
    Location
    Austria
    Posts
    1,990
    You use assignment when you want to compare for equality all over.
    Kurt

  11. #11
    Internet Superhero
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    964
    Quote Originally Posted by Elysia View Post
    Don't be afraid to touch what you haven't covered. It simply means that your instructor is either a) stuck in the past or b) has his/her priorities mixed up.
    I'd say in this case it is the latter of the two, since learning about dynamic memory allocation and file I/O before vectors is completely backwards. Unless of course he's secretly teaching C, probably even without being aware of it.
    How I need a drink, alcoholic in nature, after the heavy lectures involving quantum mechanics.

  12. #12
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Code:
            cout << "First and Last Name : " << endl;
            string name;
            getline(cin, name, '\n');
            cin >> name;
    Here you call getline then you use >> .

    These are two different ways of reading something from cin and putting the result in "name". If you read those links...
    getline will read up to the newline. It won't store the newline into the buffer, but it will read it from the stream and discard it.
    >> will read "a word", that is, it'll read up to the first whitespace. It won't read the whitespace, nor discard it. It'll leave it, so the next read from the stream will read that whitespace.

    I think you're aware of the latter, since you put a cin.ignore() earlier.

    So - the code will wait for user input at getline(). If the user enters "John Smith", "John Smith" will be written into name, and the newline discarded.
    Then the code will wait for user input at cin >>. If something is input, name will be overwritten with that.

    For the crash, do read the feof() link vart posted. You should be able to understand the problem from that. There are several possible ways to solve the problem in C++. There's a very C++y way to do it, but the way it works is somewhat beyond your current knowledge, so it's probably best to go for a simpler approach. Or google until you find the answer Then read this: How does that funky while (std::cin >> foo) syntax work?, C++ FAQ

    Quote Originally Posted by worl4125
    Yeah, I'm afraid we haven't touched on vectors as yet
    +1 to "have a look". The split() function has a very C-like style -- a counting loop to determine the size, then allocation, then populating the allocated memory. Vectors eliminate the need to manually allocate memory, as they grow dynamically. A lot like 'string' objects vs manually allocating fixed size char buffers.

  13. #13
    Registered User
    Join Date
    Aug 2013
    Posts
    33
    Ok, I've made some corrections Thanks for the feof() FAQ vart, it was helpful. Although I'm still not sure how the buffer flush one works, but I'll study that a bit more. Also I'll take a look at the vectors (especially since I keep hearing everyone talk about them.)

    As for the code, I think I have it down to two issues.

    writeData() works correctly except that the loop isn't working right. I feel like its something simple that I'm over looking but I don't see it. The problem has to do with the code for "Enter Another Record (Y/N)?" A "N" answer should call back up the menu() function, while a "Y" answer should continue the loop. However both answers are calling the menu() at the moment.

    readData() is looking except for the fact it keeps going beyond the last record and generates all sorts of symbols. The records themselves break up like they're supposed to, so I'm assuming that the professor's split() function works as intended, but I get a debugging error:

    First-chance exception at 0x63086D46 (msvcp110d.dll) in Lab07.exe: 0xC0000005: Access violation reading location 0xFDFDFDFD.
    Unhandled exception at 0x63086D46 (msvcp110d.dll) in Lab07.exe: 0xC0000005: Access violation reading location 0xFDFDFDFD.

    I'm not sure if this is a problem with the split() function, my code in readData(), or the first problem with writeData() not looping like it should. Google search of the error code reveals something about trying to use a freed variable, although I'm not really understanding it.

    Updated code is below and a screenshot of my current output is attached.
    And thanks for the help guys.

    Code:
    #include <iostream>
    #include <fstream>
    #include <string>
    using namespace std;
    
    void menu(void);
    void writeData(void);
    void readData(void);
    string * split(string theLine, char theDeliminator);
    
    const char FileName[] = "C:\\Users\\User\\Documents\\Visual Studio 2012\\Projects\\Lab07\\Lab07\\TestAddress.txt";
    int main () 
    {
        menu();
        system("pause");
        return 0;
    } 
    
    void menu(void)
    {
        char answer;
    
        do
        {
        cout << "Welcome to the Address Database." << endl;
        cout << "Do you wish to (A)ppend records, (D)isplay records, or (E)xit the program?" << endl;
        cin >> answer;
        cin.ignore();
        
            switch (answer)
            {    
                case 'A':; case 'a':;
                writeData(); 
                break;
                case'D': case 'd':;
                readData();
                break;
                case'E': case 'e':;
                exit (EXIT_SUCCESS);
                break;
                default:
                cout << "Invaild selection" << endl;
            }
        }
        while ((answer != 'E') || (answer != 'e'));
    }
    
    
    void writeData(void)
    {
        char answer;
        
        ofstream AddInfo("C:\\Users\\User\\Documents\\Visual Studio 2012\\Projects\\Lab07\\Lab07\\TestAddress.txt",ios::app);
    
        if (AddInfo.is_open())
        {
            do
            {
                cout << endl;
                cout << "First and Last Name : " << endl;
                string name;
                getline(cin, name, '\n');
    
                cout << endl;
                cout << "Street Address: " << endl;
                string address;
                getline(cin, address, '\n');
    
                cout << endl;
                cout << "City: " << endl;
                string city;
                getline(cin, city, '\n');
    
                cout << endl;
                cout << "State: " << endl;
                string state;
                getline(cin, state, '\n');
        
                cout << endl;
                cout << "Zip Code: " << endl;
                string zip;
                getline(cin, zip, '\n');
    
                AddInfo << name << "," << address << "," << city << "," << state << "," << zip << endl;
    
                cout << endl;
                cout << "Enter Another Record? (Y/N)" << endl;
                cin >> answer;
                if (answer = 'N' || (answer = 'n'))
                {
                    menu();
                } 
                cin.ignore();
            }
            while (answer = 'Y' || (answer = 'y'));
        
        }
        else
        {
            cout << "Could not open file." << endl;
        }
        AddInfo.close();
    }
    
    void readData(void)
    {
        string name, address, city, state, zip;
        ifstream AddInfo("C:\\Users\\User\\Documents\\Visual Studio 2012\\Projects\\Lab07\\Lab07\\TestAddress.txt", ios::in);
        string lineBuffer;
        
        if (AddInfo.is_open())
        {
            AddInfo >> lineBuffer;
            while(AddInfo.good())
            {
                getline(AddInfo, lineBuffer, '\n');
                string *theFields = split(lineBuffer, ',');
                cout << "SHOW RECORDS" << endl;
                cout << "---------------------------------" << endl;
                cout << "Name............ " << theFields[0] << endl;
                cout << "Street Address.. " << theFields[1] << endl;
                cout << "City............ " << theFields[2] << endl;
                cout << "State........... " << theFields[3] << endl;
                cout << "Zip Code........ " << theFields[4] << endl;
                cout << "---------------------------------" << endl;
            }
        AddInfo.close();
        }
        else
        {
            cout << "Unable to open file." << endl;
        }
    }
    
    string * split(string theLine, char theDeliminator)//Useage: string *theFields = split(lineBuffer, ',');
    {
        int splitCount = 0;
        for(int i = 0; i < theLine.size(); i++)
        {
            if (theLine[i] == theDeliminator)
            splitCount++;
        }
        splitCount++;  
            
        string* theFieldArray; 
        theFieldArray = new string[splitCount]; 
            
        string theField = "";
        int commaCount = 0;
    
        for(int i = 0; i < theLine.size(); i++)
        { 
            if (theLine[i] != theDeliminator) 
            {
                theField += theLine[i]; 
            }
            else 
            { 
                theFieldArray[commaCount] = theField; 
                theField = "";
                commaCount++;
            }
        }
    theFieldArray[commaCount] = theField; 
    
    return theFieldArray;
    }
    Attached Images Attached Images

  14. #14
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by worl4125 View Post
    I'm not sure if this is a problem with the split() function, my code in readData(), or the first problem with writeData() not looping like it should. Google search of the error code reveals something about trying to use a freed variable, although I'm not really understanding it.
    Most likely, it is in your split function. That's understandable. You're dealing with things on a very low level here. It's easy to get wrong. That's exactly why we have vector. It makes so we don't have to worry about these details.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  15. #15
    Registered User
    Join Date
    Mar 2010
    Posts
    583
    Your Y/N problem is because of:

    Quote Originally Posted by ZuK View Post
    You use assignment when you want to compare for equality all over.
    You're not checking "answer", you're assigning 'n' to it!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. domain split function
    By net1 in forum C Programming
    Replies: 3
    Last Post: 06-07-2010, 06:59 AM
  2. Help me with split function.
    By Milhas in forum C Programming
    Replies: 9
    Last Post: 03-30-2008, 05:03 PM
  3. split function
    By eXistenZ in forum C++ Programming
    Replies: 11
    Last Post: 04-18-2005, 01:06 PM
  4. CString split function ?
    By eXistenZ in forum Windows Programming
    Replies: 2
    Last Post: 02-18-2005, 10:25 AM
  5. Split function
    By fkheng in forum C Programming
    Replies: 7
    Last Post: 07-08-2003, 08:26 PM