Thread: file I/O cin.get

  1. #1
    Registered User
    Join Date
    Feb 2003
    Posts
    12

    file I/O cin.get

    I intially get this program working using getline, however, I need to search for a certain character in a line of text and reaplce it with another. The program is supposed to prompt a user to input a question(which is ignored) and will then read a 1 line "answer" from a text file that contains 8 different 1 line answers. After the first and with each subsequent answer, the user is prompted if they want to ask another question. I have it working where it will read the first line from the text file, however, the program stops there.
    Any assistance would be appreciated.

    Thanks

    Code:
    #include <fstream>
    #include <iostream>
    #include <cstdlib>
    using namespace std;
    using std::ifstream;
    
    newLine(ifstream& inStream);						
    const int NUMBER_OF_CHAPTERS=20;
    
    int main()
    {
    char doesntmatter[100];							
    char question=0;								
    int number_of_answers=0;					
    ifstream inStream;
    					
    
    	do
    	{	
    	inStream.open("A:\\answerfile.txt");	
    	cout<<"Please enter a question:"<<endl;		
    	cin.getline(doesntmatter, 100, '\n');
    	char next;
    	
    		inStream.get(next);		
    while (! inStream.eof())
    {
    	while(next != '\n')
    	{
    		if(next=='#')
    		cout<<NUMBER_OF_CHAPTERS;
    	
    		else
    		cout<<next;
    	inStream.get(next);
    	
    	}
    }
    	cout<<"Would you like to ask another question, y or no:"<<endl;
    	cin>>question;								
    	cin.ignore();
    	number_of_answers++;						
    	if(number_of_answers==7)
    	{
    		inStream.close();							
    		inStream.open("A:\\answerfile.txt");			
    	}
    	
    	}while(question=='y'||question=='Y');		
    
    	return 0;
    }
    The text file looks like:
    Test answer number #.
    This is another test answer.
    This is yet another test answer.
    This is even yet another test answer.
    This is test answer number five.
    This is test answer number six.
    This is test answer number seven.
    This is test answer number eight.

  2. #2
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    "I intially get this program working using getline, however, I need to search for a certain character in a line of text and reaplce it with another."

    I'm not sure why you switched from using getline(), but get() leaves the \n in the stream, and \n is the default delimiter for get(), so you can't get by the \n at the end of the first line. On the other hand, getline() reads and discards the delimiter.

    You could use cin.ignore() at the end of every line, but it seems easier to use getline().

  3. #3
    Registered User
    Join Date
    Feb 2003
    Posts
    12
    I don't think that I understand getline entirely. Is it correct that it stores the line of text as a C-String?. Would I then need to read the line into an array in order to search for a specific character and in this case, replace it with something else?.

    Thanks.

  4. #4
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    "I don't think that I understand getline entirely. Is it correct that it stores the line of text as a C-String?"

    So does get(). They both read in the data, and then tack on a \0 at the end.

    "Would I then need to read the line into an array in order to search for a specific character and in this case, replace it with something else?"

    You have to read it into a char array to start with, just like with get(), so you're ready to start checking. The only difference between get() and getline() is the fact that get() does not remove the delimiter and getline() does. If you do this:

    char text[50];
    cin.getline(text, 50);

    getline() will read in 49 characters maximum or until it encounters a '\n'(which occurs when you hit the return key), whichever occurs first, and then it tacks on '\0' to the end for a total of 50 char's.

    What if you want to read in multiple lines of text but the user hits return between the lines? You can specify a third parameter with getline() and get(), called a delimiter. The default delimiter is '\n', but you can specify, say '#' as the delimiter, and then getline() won't stop reading until it reads in a "#" char. If you do this:

    char text[500];
    cin.getline(text, 500, '#');

    you can instruct the user to enter as many lines of data as they want, and then have them terminate their data with '#' and hit return, and then getline() will read in 499 char's max, including the '\n' char's at the end of the lines, or until it reads the '#' delimiter.

    Try it out.
    Code:
    #include <iostream>
    using namespace std;
    
    int main()
    {
    	char text[500];
    	cout<<"Enter multiple lines of text separated by hitting return."
    		<<endl
    		<<"When you are done, type in a '#' symbol, and hit return."
    		<<endl;
    
    	cin.getline(text, 500, '#');
    
    	cout<<"You entered:\n"
    		<<text
    		<<endl;
    	
    	return 0;
    }

  5. #5
    Registered User
    Join Date
    Jan 2003
    Posts
    311
    7stud, the OP is using a version of get that takes a single char as a paramiter. The normal way of doing this is:
    Code:
    char next;
    while(inStream.get(next) && next != '\n') {
        if(next == '#') cout << " I'm doing hash ";
        else cout << next;
    }
    This avoids subtle problems that appear to be the OP's difficulties. Namely this
    Code:
    while (! inStream.eof())  
    // eof() is not set if the file was not 
    // opened or has some other error 
    // eof() should only be used after
    // file processing has finished to veryfy
    // that the entire file was consumed.
    {
    	while(next != '\n')
    	{
    		if(next=='#')
    		cout<<NUMBER_OF_CHAPTERS;
    	
    		else
    		cout<<next;
    	inStream.get(next); 
    // this line is never reached if next == '\n'
    // this is the only line that consumes
    // characters so the file never reaches
    // eof.
    // This is your bug.	
    	}
    }
    There are some other bugs in the use of ignore, I find this utility function is usefull enough that it should have been encluded in the standard library
    Code:
    inline
    bool eat(std::istream &is, char term) {
        char ch;
        while(is.get(ch)) {
            if(term == ch) return true;
        }
        return false;
    }
    use eat(cin,'\n') whenever you want to throw away the current line in the buffer. After asking your question and after asking if you want to ask another question. The other problem is where you re-open your answer file you do not reset number of answers to zero. after the first seven anwers it will repeat the entire file an then loop forever. This is where eof() is used.
    Code:
    if(!inStream.good()) {
        if(inStream.eof()) {
            inStream.close();
           inStream.open("A:\\answerfile.txt");
        } else {
            cout << "Problem with answerfile" << endl;
             return 2;
        }
    }

  6. #6
    Registered User
    Join Date
    Feb 2003
    Posts
    12
    With your combined suggestions, I feel that I am one step closer to figuring this out. What I am trying to do is prompt the user for a irrelevant question and then the program will provide a one line "answer" to the question. If the answer contain a # sign, the program will replace it with a number, which is the const NUMBER_OF_CHAPTERS. The program should then prompt the user if they would like to enter another question. If yes, another question is entered and then the second line of the text file is read which contains the second answer. With this code
    [code]
    char next;
    while(inStream.get(next) && next != '\n') {
    if(next == '#') cout << " I'm doing hash ";
    else cout << next;
    }
    ]/code]
    I am getting all of the lines in the text file.

    Hopefully this clarifies what I am trying to do.

    Thanks for the input.

  7. #7
    Registered User
    Join Date
    Jan 2003
    Posts
    311
    That block of code reads only one line from the file. My guess is that you have wrapped it in while(!inStream.eof()) or something. Still, I wasn't sure so I went ahead and wrote the damm thing, here you go
    Code:
    #include<iostream>
    #include<fstream>
    #include<string>
    
    using std::cout;
    using std::endl;
    
    int main() {
        const char filename[] = "answer.txt";
        std::ifstream in(filename);
        std::string question;
        while(in) {
    // This is the main loop, if we are in here we know the 
    // file is open and ready to provide data
    
            cout << "Ask your question or \"quit\" to quit: ";
            getline(std::cin,question);
            if(question == "quit") break;
    // this avoids annoying do you want to quit? questions and
    // provides a single exit point. We could also just return
    // from here. case-sensitive.
    
            char ch;
            while(in.get(ch) && ch != '\n') {
                if(ch == '#') cout << 42;
                else cout << ch;
            }
            in >> std::ws; // Eat whitespace
            cout << endl;
    // copies and parses the line, we eat whitespace mostly
    // to handle the case of the final answer, with the 
    // side-effect that we ignore leading spaces for 
    // answers after the first.
      
            if(in.eof()) {
                in.close();
                in.clear(); // open does not clear flags?!?
                in.open(filename);
            }
    // here we check to see if we have run out of answers, and
    // open/close to reset the file.  We could also do .seekg(0);
    // in any case, we must clear() the stream.
        }
    // exiting main loop.
        if(in) { 
            return 0;
        } else {
            std::cerr << "Problems occurred with " << filename << endl;
            return 1;
        }
    // here we check to see why we are no longer ansering questions,
    // and tell the user if there was a problem with the file.
    
    }
    You may have to change this slightly.

  8. #8
    Registered User
    Join Date
    Jan 2003
    Posts
    311
    You can leave out the in >> std::ws; if you don't have a newline on your final answer. Not sure why I added it.

  9. #9
    Registered User
    Join Date
    Feb 2003
    Posts
    12
    Grib, thanks for putting that together. Here is what I had done. There are 2 problems. The first is that there is a character following the #. After the program outputs the 1 answer and substitutes the number_of_chapters variable, the next time through it outputs the "N" which is the character following the #. Also, there are a total of 8 one line answers in the text file. After the program cycles though all 8, it is supposed to close, re-open and read through them again, however, the next pass through it should subtract 1 from the number_of_chapters variable. It is not doing that. While it does keep prompting for a question, after it goes through the 8 answers, I am not getting any further output.

    Thanks for the help with this.
    Code:
    #include <fstream>
    #include <iostream>
    #include <cstdlib>
    using namespace std;
    using std::ifstream;
    
    newLine(ifstream& fin, int number_of_answers);	//declare function
    
    int main()
    {
    char doesntmatter[100];							//declare array for ignored input
    char question=0;								//prompt for y or n input
    int number_of_answers=1;						//counter for answer reset
    
    ifstream fin;
    	fin.open("A:\\answerfile.txt");				//open text file
    
    	do
    	{		
    	cout<<"Please enter a question:"<<endl;		//prompt for question input
    	cin.getline(doesntmatter, 100, '\n');
    	newLine(fin, number_of_answers);
    	cout<<"Would you like to ask another question, y or no:"<<endl;
    	cin>>question;								
    	cin.ignore();
    	number_of_answers++;						//increment answer counter
    	
    	if(number_of_answers==7)
    	{
    		fin.close();							//close file
    		fin.open("A:\\answerfile.txt");			//re-open file
    	}
    	}while(question=='y'||question=='Y');		//test for y answer
    
    	return 0;
    }
    
    newLine(ifstream& fin, int number_of_answers)
    {
    	char answerfile[100];
    	int NUMBER_OF_CHAPTERS=20;
    
    	if(number_of_answers==1)
    	{
    	
    		fin.getline(answerfile,100,'#');
    		cout<<answerfile<<NUMBER_OF_CHAPTERS<<endl;
    
    	}
    	else if(number_of_answers>1 && number_of_answers <7)
    	{
    		fin.getline(answerfile, 100, '\n');
    		cout<<answerfile<<endl;
    	}
    	NUMBER_OF_CHAPTERS--;
    
    	return 0;
    	
    }
    The text file contains:
    I'm not sure but I think you will find the answer in Chapter #N.
    That's a good question.
    If I were you, I would not worry about such things.
    That question has puzzled philosophers for centuries.
    I don't know. I'm just a machine.
    Think about it and the answer will come to you.
    I used to know the answer to that question, but I've forgotten it.
    The answer can be found in a secret place in the woods.

  10. #10
    Registered User
    Join Date
    Jan 2003
    Posts
    311
    I am not sure what else I can do besides provide you with a complete working program. When you re-open the file you are not clearing the flags. NUMBER_OF_CHAPTERS is a local variable and thus is always re-initialized to 20. ALL CAPS is used only for macros by convention. number_of_ansers is not reset to 1 when you re-open the file.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Data Structure Eror
    By prominababy in forum C Programming
    Replies: 3
    Last Post: 01-06-2009, 09:35 AM
  2. File I/O Assertion Failure in VS2008
    By clegs in forum C Programming
    Replies: 5
    Last Post: 12-25-2008, 04:47 AM
  3. Game Pointer Trouble?
    By Drahcir in forum C Programming
    Replies: 8
    Last Post: 02-04-2006, 02:53 AM
  4. Unknown Memory Leak in Init() Function
    By CodeHacker in forum Windows Programming
    Replies: 3
    Last Post: 07-09-2004, 09:54 AM
  5. advice on file i/o
    By Unregistered in forum C Programming
    Replies: 1
    Last Post: 11-29-2001, 05:56 AM