Thread: I just can't get() it.

  1. #1
    Registered User
    Join Date
    Sep 2012
    Posts
    32

    Angry I just can't get() it.

    I've got an overdue assignment for a data structures class, and I am having the largest problem with reading in data from a text file. The program is essentially recreating Akinator with a binary seach tree holding the data. Below is the relevant code:

    Code:
    //header file
    class game{
    public:
        string ans;
        BST<string> data;
        BSTNode<string>* item;
        fstream datafile;
        string newQuestion;
        const char* receive;
    
        game();
        void collect(const char* filename);
        string getAns(){
            return ans;
        }
    
        void ask(BSTNode<string>* item, string ans);
        int askQuestion(BSTNode<string>* item, string ans, int i);
        void getQuestion(ostream& ostrm);
        void appendTree(string ques, string ans){
            datafile << ans << ": " << ques << "\n";
        };
    };
    
    //section where I need the help
    void game::collect(const char* filename){
    
        int size = 30;
    
        datafile.open(filename, ios::in);
        if(!datafile)
            fatal("Error opening stream!");
         
        for(;;) {
            getline(datafile, receive, ",");                //here's the lil' ........er
            if(datafile.eof())
                break;
            data.insert(receive);
        }
    
        if (data.isEmpty()){
                cout << "No data in database file. You'll need to make a question first." << endl;
                getQuestion(cout);
        }
        
        datafile.close();
    
    }
    (I should point out a few things. First, assume I put "using namespace std" in another header file. Also, there are a few things, such as fatal() and anything BST related, that are abstract. Those are unrelated to my problem. receive has been initialized to 256 characters in the constructor. Lastly, I need to write to the same file I read from, hence fstream.)

    I absolutely cannot use any variation of the get() function to read the data in from a text file. Layout looks something like:

    cat: has 4 legs, has tail, has fur

    Before I even worry about the colon, I want to focus on the commas. These are the following solutions I've tried:

    Code:
    dataline.get(receive, size, ",");
    dataline.getline(receive, size, ",");
    dataline.get(receive, size);
    dataline.getline(receive, size);
    getline(dataline, receive);
    getline(dataline, receive, ",");
    Without fail, the following errors appear:

    IntelliSense: no instance of overloaded function "getline" matches the argument list

    (this one appears a few times per variable format involved) error C2784: 'std::basic_istream<_Elem,_Traits> &std::getline(std::basic_istream<_Elem,_Traits> &,std::basic_string<_Elem,_Traits,_Alloc> &)' : could not deduce template argument for 'std::basic_istream<_Elem,_Traits> &' from *insert variable format here*

    error C2780: 'std::basic_istream<_Elem,_Traits> &std::getline(std::basic_istream<_Elem,_Traits> &&,std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem)' : expects 3 arguments - 2 provided

    I have spoken to multiple teachers, scoured the interwebs, created new project files in the compiler, updated the compiler and service packs to the latest versions, etc. I've tried it all, it still doesn't work, and I'm about ready to chuck my laptop across the room in anger. Is there anyone out there who can give me some sort of solution to this consistent nightmare?

  2. #2
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    std::getline() is for std::strings only, and the prototype is something like this:

    Code:
     getline( readfromfile, string, delimiter );
    Character arrays (or pointers simulating them) can be read with istream::getline, meaning that you can use any stream that you can read from, and the prototype is something like:

    Code:
    fromfile.getline( array, arraysize, delimiter );
    Notably, the array must not be const qualified, so since your code uses a const char * it doesn't work.

    std::basic_istream::getline - cppreference.com
    std::getline - cppreference.com

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by William Putnam
    assume I put "using namespace std" in another header file
    That is horrible: using directives should not be in file scope in a header file. Therefore, if I assume this, I assume that you are guilty of a bad practice. Rather, move the using directive from the header file to this source file, and fully quality those names in the std namespace that are used in that header file.

    Quote Originally Posted by William Putnam
    Code:
    void collect(const char* filename);
    On one hand, this is arguably fine. On the other hand, just have it as:
    Code:
    void collect(const std::string& filename);
    then call c_str() in collect if needed. Actually, I think it would be better to get rid of the fstream member variable named datafile and then write:
    Code:
    void collect(std::fstream& datafile);
    Or just have a local std::fstream variable. At the moment, your datafile member variable looks suspiciously like a global variable disguised as a member variable.

    This is wrong:
    Code:
    getline(datafile, receive, ",");
    receive is a const char*. There is no way you can read using it. What you probably want to do is to change receive to be a std::string instead. Once you do that, you can change this:
    Code:
    getline(datafile, receive, ",");
    if(datafile.eof())
        break;
    to:
    Code:
    if (!getline(datafile, receive, ",")) {
        break;
    }
    Wait a minute, I see that this code is followed by:
    Code:
    data.insert(receive);
    Frankly, it once again looks like receive is a global variable disguised as a member variable. I suggest that you get rid of the member variable, then declare a local variable named receive (of type std::string)
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    Registered User
    Join Date
    Sep 2012
    Posts
    32
    Code:
    void game::collect(const char* filename){
    
        int size = 30;
        string receive;
    
        datafile.open(filename, ios::in);
        if(!datafile)
            fatal("Error opening stream!");
         
        for(;;) {
            if (!getline(datafile, receive, ","))
                break;
            data.insert(receive);
        }
    
        if (data.isEmpty()){
                cout << "No data in database file. You'll need to make a question first." << endl;
                getQuestion(cout);
        }
        
        datafile.close();
    
    }
    laserlight, I've tried the if statement with the getline, declared receive locally, and am still getting the same errors.

    Also, the using namespace std is part of a package header file provided by my university's CS department for assignments.
    And I appreciated the advice on the parameters for the function, but I have the variables being declared a certain way, and this configuration works fine for me. But thanks for the pointers, I will use those in future programs.

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Oh. You're passing a string literal as the delimiter, but it should be a char:
    Code:
    if (!getline(datafile, receive, ','))
    Quote Originally Posted by William Putnam
    Also, the using namespace std is part of a package header file provided by my university's CS department for assignments.
    Ah, then you should keep in mind that whoever wrote this is not familiar with C++ good practices.

    EDIT:

    Actually, come to think of it, you should replace the controlled infinite loop with a while loop:
    Code:
    while (getline(datafile, receive, ',')) {
        data.insert(receive);
    }
    Quote Originally Posted by William Putnam
    And I appreciated the advice on the parameters for the function, but I have the variables being declared a certain way, and this configuration works fine for me. But thanks for the pointers, I will use those in future programs.
    Yeah, because as your programs get bigger and more complex, you will probably find that having your variables in a smaller scope where appropriate makes it easier to reason about your programs, and hence you will write fewer bugs and have an easier time debugging.
    Last edited by laserlight; 05-07-2013 at 10:15 PM.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User
    Join Date
    Sep 2012
    Posts
    32
    laserlight, i am both amazed at your expertise and angered at my inability to forget the difference between single quotes and double quotes.
    the problem is fixed now, thank you!

Popular pages Recent additions subscribe to a feed

Tags for this Thread