简体   繁体   中英

Modifying this function to read from a ';' separated file

Disclaimer this is for a homework question. Not asking for a full solution to the program I am writing, just asking for better understanding of what is happening. Thanks in advance.

The provided function is reading from a file that looks like this.

foo;bar
foo;bar

And I would like to modify the function to read from a file that looks like

foo;bar;foobar
foo;bar;foobar

The provided function looks like

void EntryList::loadfile(const char filefoo[])
{
    ifstream        in;
    char            foo[MAX_CHAR];
    char            bar[MAX_CHAR];
    AddressEntry    anEntry;    

    in.open (filefoo);
    if(!in)
    {
        in.clear();
        cerr << endl << "Fail to open " << filefoo << " for input!" << endl << endl;
        exit(1);
    }   

    in.get(foo, MAX_CHAR, ';');
    while (!in.eof())
    {
        in.get();                       //remove field seperator ';'            
        in.get(bar, MAX_CHAR, '\n');
        in.ignore(100, '\n');               //remove record seperator '\n'  

        anEntry.setfoo(foo);
        anEntry.setbar(bar);    

        addEntry(anEntry);  

        in.get(foo, MAX_CHAR, ';');             //start the next record
    }
    in.close();
}

The function that I modified looks like

void EntryList::loadfile(const char fileName[])
{
    ifstream        in;
    char            foo[MAX_CHAR];
    char            bar[MAX_CHAR];
    char            foobar[MAX_CHAR];
    TaskList        theEntry;   

    in.open(fileName);
    if (!in) {
        in.clear();
        cerr << endl
        << "Failed to open "
        << fileName
        << " for input!" << endl << endl;
        exit(1);
    }   

    in.get(foo, MAX_CHAR, ';');
    while (!in.eof())
    {
        in.get(); // rm ;
        in.get(bar, MAX_CHAR, ';');
        in.get(foobar, MAX_CHAR, '\n'); // rm '\n'
        in.ignore(100, '\n');   

        theEntry.setfoo(foo);
        theEntry.setbar(bar);
        theEntry.setfoobar(foobar); 

        addEntry(theEntry); 

        in.get(foo, MAX_CHAR, ';'); 

    }   

    in.close(); 

}

I am in the middle of rewriting this program for at least the 4 time. and I have modified the file how I (humanly) think I should to this. I have had issues in the past, doing it this way. (still working on the other parts of the program so I cannot be too specific right now, but I know my results were unexpected ) So my question is does the function that I modified look correct for what I am trying to do? Am I off by one? I guess I am struggling with understanding how the original function is working. (step by step systematically.) hence my confusion about my modified function.

I can also provide any other functions you would like to take look at, my setters and getters. Also if you have any questions or feedback I would appreciate it greatly.

Both the orginal and the modified functions are wrong: you alway need to check for successful input after trying to read something (I guess, if I eventually pass away my headstone will have that engraved...). Using in.eof() to control an input loop in general does not work!

If the line ends in a string with less than MAX_CHAR characters, the next line get ignored: you need to check if the input ends in a newline character and, if not, ignore the remaining character. If the last input ends with a newline character, you don't want to ignore characters. Also, if the line happens to end in a string with more than 100 characters, it also doesn't work. The magical constant for std::istream::ignore() to ignore as many characters as necessary is, inconveniently, spelled std::numeric_limits<std::streamsize>::max() and is declared in the header <limits >.

Basically, your loop should start with

while (in.getline(foo, MAX_CHAR, ';')
         .getline(bar, MAX_CHAR, ';')
         .get(foobar, MAX_CHAR, '\n')) {
    if (foobar[in.gcount() - 1] == '\n') {
        foobar[in.gcount() - 1] = '\0';
    }
    else {
        in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    }
    // process the inputs
}

The code uses std::istream::getline() for the first two components to avoid the separate to be stored: it is sufficient if the separator is extracted and the input is stopped. For the last component std::istream::get() is used because it is necessary to verify if the last character stored was a newline. The last character stored is access using std::istream::gcount() which contains the number of characters stored by the last unformatted input function. Since the input succeeded and it would stop either when storing a newline or after storing MAX_CHAR characters, in.gcount() - 1 is always a valid index. Note, however, that the code is not tested...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM