Thread: cin.getline in reading files?

  1. #1
    Registered User
    Join Date
    Aug 2001
    Posts
    154

    Question cin.getline in reading files?

    The code below works in writing tool.toolName, tool.quant, and tool.cost into a file when toolName is one word ("hammer", e.g.). But it doesn't work when toolName is more than one word ("power drill", e.g.). I've tried using cin.getline(line, 20), cin.getline(tool.toolName, 20), etc, but can't get it to work. toolName is a char[20]. I could try string, but since this is supposed to be a fixed length record, I don't know how to limit a string length either. Any ideas? Thanks.
    Code:
    if (tool.recNum == 0)
    	{
    		cout << "\nEnter tool name, quantity and cost: ";
    		cin >> tool.toolName >> tool.quant >> tool.cost;
    		tool.recNum = rec;
    		toolFile.seekp((rec - 1) * sizeof(toolList));
    		toolFile.write((char *)&tool, sizeof(toolList));
    	}

  2. #2
    Registered User Strider's Avatar
    Join Date
    Aug 2001
    Posts
    149
    What exactly is cin.getline() doing when you use it? In most cases it should work. Do you use cin with the Extraction operator prior to cin.getline()? If so, the linefeed character is probably still in the buffer and is read in with the cin.getline() function which will take it as its only input (delimited by '\n'). Maybe post your code with the cin.getline() call and I can help you from there.

    David
    One Ring to rule them all, One Ring to find them,
    One Ring to bring them all and in the darkness bind them
    In the Land of Mordor where the Shadows lie.

  3. #3
    Registered User WayTooHigh's Avatar
    Join Date
    Aug 2001
    Posts
    101
    try this:
    cin.getline(line, 20, '\n')

    this will get all the text until the Enter key is pushed
    Sometimes, the farthest point from the center is the center itself.

    Your life is your canvas, it's only as beautiful as you paint it.

  4. #4
    Registered User Strider's Avatar
    Join Date
    Aug 2001
    Posts
    149
    '\n' is the default delimeter.

    What I was saying, is that the >> operator when used with cin will read characters from the keyboard buffer into an object. It will not read in most special characters, including '\n'. The '\n' character only tells the operator that it is done extracting the input and then it is left sitting in the keyboard buffer. Now using cin >> will handle any characters left in the buffer by flushing it first. The cin.getline() call will not. It will only see the '\n' character, which is by default the delimeter for cin.getline(), and think that it is done.

    Now again, if this is the problem, you could specify another delimeter for your input, although this can be annoying as most people are used to hitting the enter key after typing something in. An easier way to handle it is to use cin.ignore() prior to the cin.getline() call:
    Code:
    // EXAMPLE
    
    cin >> someValue;
    
    // just used the >> operator and we want to follow with getline()
    // the nasty little '\n' character is just waiting to screw us up,
    // so let's ignore it.
    cin.ignore();
    
    cin.getline(someOtherValue, 20);
    I hope that this helps and I am not just beating the topic to death here. Again, post the altered code if the problems are steming from elsewhere and maybe I can help.

    David
    One Ring to rule them all, One Ring to find them,
    One Ring to bring them all and in the darkness bind them
    In the Land of Mordor where the Shadows lie.

  5. #5
    Registered User
    Join Date
    Aug 2001
    Posts
    154
    The whole function is below. toolName is a field in a struct named toolList.
    I've done:
    Code:
    cin.getline(tool.toolName, 20) >> tool.quant >> tool.cost;
    and
    cin.getline(tool,toolName, 20);
    cin >> tool.quant >> tool.cost;
    and (first declaring line as char[20])
    cin.getline(line, 20) >> tool.quant >> tool.cost;
    but no luck. I could use "/n", but that's the default delimiter, I believe. The whole function is below, followed by the print code, not formatted all the way yet).
    Code:
    void enterTool(fstream &toolFile)
    {
    	int rec;
    	toolList tool;
    	cout << "\nEnter a record number from 1 - 100: ";
    	cin >> rec;
    	toolFile.seekg((rec - 1) * sizeof(toolList));
    	toolFile.read((char *)&tool, sizeof(toolList));
    	if (tool.recNum == 0)
    	{
    		cout << "\nEnter tool name, quantity and cost: ";
    		cin >> tool.toolName >> tool.quant >> tool.cost;
    		tool.recNum = rec;
    		toolFile.seekp((rec - 1) * sizeof(toolList));
    		toolFile.write((char *)&tool, sizeof(toolList));
    	}
    .
    .
    .  // print code
    enterTool(hardware);
    	hardware.seekp(0);
    	cout << "Record #   Tool Name   Quantity   Cost" << endl;
    	cout << "______________________________________" << endl << endl;
    	for (int j = 0; j < 10; j++)
    	{
    		hardware.read((char *)&toolRecord, sizeof(toolList));
    		cout << toolRecord.recNum << "          " << toolRecord.toolName << "         " <<
    			toolRecord.quant << ' ' << toolRecord.cost << endl;
    	}
    Thanks for the help, I appreciate it.

  6. #6
    Registered User Strider's Avatar
    Join Date
    Aug 2001
    Posts
    149
    Have you tried cin.ignore()? Looking at your code, I see this:
    Code:
        cin >> rec;
        toolFile.seekg((rec - 1) * sizeof(toolList));
        toolFile.read((char *)&tool, sizeof(toolList));
        if (tool.recNum == 0)
        {
            cout << "\nEnter tool name, quantity and cost: ";
            cin >> tool.toolName >> tool.quant >> tool.cost;
        // continues....
    You first read in rec using:
    Code:
        cin >> rec;
    If you follow this with a
    Code:
        if (tool.recNum == 0)
        {
            cout << "\nEnter tool name, quantity and cost: ";
            cin.getline(tool.toolName, 20);
            cin >> tool.quant >> tool.cost;
    you're going to have problems. Try adding the cin.ignore() and see if that clears it up
    Code:
        if (tool.recNum == 0)
        {
            cout << "\nEnter tool name, quantity and cost: ";
            cin.ignore();  // ignores one character
            cin.getline(tool.toolName, 20);
            cin >> tool.quant >> tool.cost;
    David
    One Ring to rule them all, One Ring to find them,
    One Ring to bring them all and in the darkness bind them
    In the Land of Mordor where the Shadows lie.

  7. #7
    Registered User
    Join Date
    Aug 2001
    Posts
    154
    That didn't work by itself, but adding two cin.ignore()'s helped:
    Code:
    if (tool.recNum == 0)
    	{
    		cout << "\nEnter tool name, quantity and cost: ";
    		cin.ignore();
    		cin.getline(tool.toolName, 20);
    		cin.ignore();
    		cin >> tool.quant >> tool.cost;
    		tool.recNum = rec;
    		toolFile.seekp((rec - 1) * sizeof(toolList));
    		toolFile.write((char *)&tool, sizeof(toolList));
    	}
    Now the two word tool name is read in, but when it prints, the cost is truncated, and the initial values in tool.quant & tool.cost, 0's, are still printed as well. There's probably a simple solution, but we've learned so many different things so fast it's hard to remember them all and keep them straight. The struct used is:
    Code:
    #ifndef TOOLLIST_H
    #define TOOLLIST_H
    
    struct toolList
    {
    	int recNum;
    	char toolName[25];
    	int quant;
    	double cost;
    };
    
    #endif
    This is extra credit, so don't have to do it, but I like to figure out what's wrong & why. Sometimes it's tough to know where to start. Like now.

  8. #8
    Registered User Strider's Avatar
    Join Date
    Aug 2001
    Posts
    149
    I tried some sample code based on the pieces that you have shown and everything seems to work for me. Maybe see if you can pick out any differences that might be causing you problems.
    Code:
    #include <iostream.h>
    #include <fstream.h>
    #include <stdlib.h>
    #include <iomanip.h>
    
    struct toolList
    {
        int recNum;
        char toolName[25];
        int quant;
        double cost;
    };
    
    int main()
    {
        int rec;
        toolList tool;
        toolList toolRecord;
        fstream toolFile;
        toolFile.open("Tools.dat", ios::in|ios::out|ios::binary);
    
        if(!toolFile)
        {
            cerr << "File could not be opened." << endl;
            exit(1);
        }
    
        cout << "\nEnter a record number from 1 - 100: ";
        cin >> rec;
    
        cout << "\nEnter tool name, quantity and cost: ";
        cin.ignore();
        cin.getline(tool.toolName, 20);
        cin >> tool.quant >> tool.cost;
        tool.recNum = rec;
    
        toolFile.seekg((rec - 1) * sizeof(toolList));
        toolFile.write((const char *)&tool, sizeof(toolList));
    
        cout << "Record #   Tool Name   Quantity   Cost" << endl;
        cout << "______________________________________" 
             << endl << endl;
    
        toolFile.seekg(0);
        toolFile.read((char *)&toolRecord, sizeof(toolList));
    
        cout << setw(11) << setiosflags(ios::left) << toolRecord.recNum 
             << setw(12) << toolRecord.toolName << setw(8) 
             << setiosflags(ios::right) << toolRecord.quant << setw(7) 
             << toolRecord.cost << endl;
    	
        toolFile.close();
        return 0;
    }
    Hope this helps,
    David
    One Ring to rule them all, One Ring to find them,
    One Ring to bring them all and in the darkness bind them
    In the Land of Mordor where the Shadows lie.

  9. #9
    Registered User
    Join Date
    Aug 2001
    Posts
    154
    Well, that helps some, but still doesn't work quite right. When the program runs and asks for the user to enter tool name, quantity and cost, it hangs until any other character is entered. It also doesn't seem to overwrite the two zeros in the last two initialized fields; the quantity and cost entered display, but so do the zeros the fields have when initialized. All help is appreciated, thanks. Here's the whole code so far:
    Code:
    #include <iostream>
    #include <fstream>
    #include <cstdlib>
    //#include <iomanip>
    using namespace std;
    
    #include "toolList.h"
    
    void initialize(ofstream &);
    void enterTool(fstream &);
    void printTool(fstream &);
    
    int main()
    {
    	// Create file and initialize with 100 blank records
    	ofstream toolSet("hardware.dat", ios::binary);
    	initialize(toolSet);
    
    	// Open file for read/write, check if successful
    	fstream hardware("hardware.dat", ios::in | ios::out | ios::binary);
    	if (!hardware) 
    	{ 
    		cerr << "File not opened" << endl;
    		exit(EXIT_FAILURE);
    	}
    	
    	enterTool(hardware);	// Enter records in file
    	printTool(hardware);	// Print file to screen
    
    	return 0;				// That's all, folks!
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    // Initialize 100 blank records
    void initialize(ofstream &toolInit)
    {
    	toolList toolRecord = {0, "tool", 0, 0};	// Blank record
    
    	for (int i = 0; i < 100; i++)
    		toolInit.write((char *)&toolRecord, sizeof(toolList));	// Write blank record
    
    	toolInit.close();	// Close file
    }
    
    /////////////////////////////////////////////////////////////////////////////
    
    // Enter data into records
    void enterTool(fstream &toolFile)
    {
    	int rec;	// Record number to enter
    	toolList tool;
    
    	cout << "\nEnter a record number from 1 - 100: ";
    	cin >> rec;
    	cin.ignore();
    	toolFile.seekg((rec - 1) * sizeof(toolList));	// Move to selected record
    	toolFile.read((char *)&tool, sizeof(toolList));	// Read selected record
    	if (tool.recNum == 0)	// Make sure record is blank
    	{
    		cout << "\nEnter tool name, quantity and cost: ";
    //		cin.ignore();
    		cin.getline(tool.toolName, 25);
    		cin >> tool.quant >> tool.cost;
    		tool.recNum = rec;
    		toolFile.seekp((rec - 1) * sizeof(toolList));
    		toolFile.write((char *)&tool, sizeof(toolList));
    	}
    	else	// Record number already has data
    		cerr << "\nRecord number " << rec << " in use" << endl;
    }
    
    //////////////////////////////////////////////////////////////////////////////
    
    // Print file to screen
    void printTool(fstream &toolPrint)
    {
    	toolList toolRecord;
    	toolPrint.seekp(0);	// Begin at start of file
    	cout << "Record #   Tool Name   Quantity   Cost" << endl;
    	cout << "_______________________________________" << endl << endl;
    	toolPrint.read((char *)&toolRecord, sizeof(toolList));
    	while (!toolPrint.eof())
    	{
    		if (toolRecord.recNum != 0)
    			cout << toolRecord.recNum  << toolRecord.toolName 
    				<< toolRecord.quant << toolRecord.cost << endl;
    		toolPrint.read((char *)&toolRecord, sizeof(toolList));
    	}
    }

  10. #10
    Registered User Strider's Avatar
    Join Date
    Aug 2001
    Posts
    149
    I took your code and ran it with my struct version of toolList ( didn't know how you defined toolList.h) and everything ran fine. I hate to ask, but are you remembering to hit the enter key after entering the tool name? Unless you specify that the getline() is delimited by a space, it will just wait until the enter key is pressed. Unlike the extraction operator, getline() will read white space unless told not to. The only other possibility is that there may be something wrong in the header file or with the compiler. Let me know if you get any further.

    David
    One Ring to rule them all, One Ring to find them,
    One Ring to bring them all and in the darkness bind them
    In the Land of Mordor where the Shadows lie.

  11. #11
    Registered User
    Join Date
    Aug 2001
    Posts
    154

    Duh...

    Don't hate to ask, that was the problem. Thanks. I was trying to get all the input on one line, e. g.
    "enter tool name, quantity...", then enter sledge hammer 43 19.99 <enter>.
    Do you know of a way to do that? The struct toolList is defined a couple posts ago. I thought of using a string instead of a char[], but don't know how to specify string size, so that it's always the same for random access.
    Thanks again.

  12. #12
    Registered User Strider's Avatar
    Join Date
    Aug 2001
    Posts
    149
    Switch the order around. Have the user enter the quantity, cost and then name.
    Code:
    cout << "\nEnter quantity, cost and tool name: ";
    cin >> tool.quant >> tool.cost;
    cin.ignore();
    cin.getline(tool.toolName, 25);
    David
    One Ring to rule them all, One Ring to find them,
    One Ring to bring them all and in the darkness bind them
    In the Land of Mordor where the Shadows lie.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. reading files
    By hiya in forum C++ Programming
    Replies: 7
    Last Post: 05-21-2005, 11:40 AM
  2. Reading data from consecutively named files
    By a1pro in forum C Programming
    Replies: 10
    Last Post: 04-15-2005, 01:48 AM
  3. A little help reading from files...
    By Invincible in forum C++ Programming
    Replies: 4
    Last Post: 04-03-2002, 10:43 AM
  4. problem reading files in C
    By angelfly in forum C Programming
    Replies: 9
    Last Post: 10-10-2001, 11:58 AM
  5. Need Advice in reading files
    By jon in forum C Programming
    Replies: 4
    Last Post: 10-07-2001, 07:27 AM