I am having 2 main issues with this function:

1) For some reason my while loop is working but not correctly. If the user enters 0 rather than the while loop terminating and proceeding to the next line of code in the main function, the program begins to repeat infinite request for input information.

2) When the user needs to enter the tool name, if there is a space in the tool name the program also goes crazy and begins to output infinitely. I think that it is the function getline that can deal with also capturing a space in between strings. For example it works fine for “Hammer” but goes crazy with “Lawn mower”. How can I correct this?


My code is the following:

// user enters information, which is copied into file
      while (partNumber > 0 && partNumber <= 100)
      {
	// user enters tool name, quantity and unit price
	cout << "Enter the tool name: ";
	cin >> setw( 20 ) >> toolName;
	   
	cout << "Enter the quantity in stock and the unit price for the tool\n? ";
	cin >> inStock;
	cin >> unitPrice;

	// set the record for the part number, tool name, quantity in stock, and unit price
	tool.setPartNumber( partNumber );
	tool.setToolName( toolName );
	tool.setInStock( inStock );
	tool.setUnitPrice( unitPrice );

	// seek position in file of user-specified record   
	outTools.seekp( ( tool.getPartNumber() - 1 ) * sizeof ( Tools ) );                         

	// write user-specified information in file                   
	outTools.write( reinterpret_cast < const char * >( &tool ),sizeof ( Tools) );     
                             
	//enable user to enter another account
	cout << "Enter tool identification number (1 to 100, 0 to end input)\n? ";
	cin >> partNumber;

         } // end while loop

} // end enterRecords function

>>cin >> setw( 20 ) >> toolName;
setw() is only for output streams, it does nothing on input streams such as cin.

1) You didn't post the rest of the code so no way to answer that question. My guess is that you may need to clear the '\n' from the input keyboard buffer, which is frequently left there when entering integers. See this thread for how to do that.

u should try this:

cin.getline( toolName, 20, '\n' )

thanks this worked :)

cin >> setw( 20 ) >> toolName;

setw() is only for output streams, it does nothing on input streams such as cin.

1) You didn't post the rest of the code so no way to answer that question. My guess is that you may need to clear the '\n' from the input keyboard buffer, which is frequently left there when entering integers. See this thread for how to do that.

Hello,
Thank you I was able to get the entire tool name through the getline function. I also tried to change my while loop. I would like the program to stop requesting tool information input as soon as the user enters the sentinel value, 0. But when 0 is entered, the program still outputs infinitely. 0 would cause the enterRecords() function to end and the processChoice() function to occur, to call the enterChoice() function then back to the switch statement in order to process the users input. But I am not sure why it is infinitely outputing the user’s choice request. Maybe there is something wrong with my swtich statement.

My code is the following:

// default Tools constructor
Tools::Tools( int partNumberValue,string toolNameValue, int inStockValue, double unitPriceValue)
{
    setPartNumber( partNumberValue);
    setToolName( toolNameValue );
    setInStock( inStockValue);
    setUnitPrice( unitPriceValue );
} // end Tools constructor


// get tool identification number 
int Tools::getPartNumber() const
{
    return partNumber;
} 
// set tool identification numbers
void Tools::setPartNumber( int partNumberValue)
{
   partNumber = partNumberValue; 
} 
void Tools::validatePartNumber(int checkPart)
{
    if(checkPart > 0 && checkPart <= 100)
        partNumber = checkPart;
    else
    {
        bool flag = false;
        while(flag == false)
        {
            cout << "Part number is a record, an integer within range 1 to 100.";
            cout << "\nRe-enter tool identification number (1 to 100, 0 to end input)\n? ";
            cin >> checkPart;

            if(checkPart > 0 && checkPart <= 100)
            {
                partNumber = checkPart;
                flag = true;
            }
        } // end while loop
    } // end if 
} // end function

// get tool name
string Tools::getToolName() const
{
   return toolName;
} 
// set the tool name
void Tools::setToolName(string toolNameString)
{
   // copy at most 20 characters for the tool name
    const char *toolNameValue = toolNameString.data();
    int length = int(toolNameString.size());
    length = (length < 20 ? length : 19);
    strncpy(toolName, toolNameValue, length);
    //toolName[ length ] = '\0'; // append null character to lastName
} 

// get in-stock quantity for the tool 
int Tools::getInStock() const
 {
    return inStock;
 } 
 // set in-stock quantity for the tool
void Tools::setInStock( int inStockValue)
{
   inStock= inStockValue; 
} 

// get unit price for each tool
double Tools::getUnitPrice() const
{
    return unitPrice;
} 
// set unit price for each tool
void Tools::setUnitPrice( double unitPriceValue )
{
    unitPrice = unitPriceValue;
} 
void Tools::createAndInitializeTextFile()
{
    ofstream outTools( "hardware.dat", ios::out | ios::binary );

       // exit program if ofstream could not open file
    if ( !outTools )
   {
        cerr << "File could not be opened." << endl;
        exit( 1 );
   } 

   Tools blankTool; // constructor zeros out each data member

   // output 100 blank records to file
   for ( int i = 0; i < 100; i++ )
      outTools.write( reinterpret_cast < const char * >( &blankTool ), sizeof ( Tools ) );    
}

void Tools::enterRecords()
{
     fstream outTools( "hardware.dat", ios::in | ios::out | ios::binary );

    // exit program if fstream cannot open file
    if ( !outTools )
    {
       cerr << "File could not be opened." << endl;
       exit( 1 );
    } // end if

    // require user to specify a tool identification number
    cout << "Enter tool identification number (1 to 100, 0 to end input): ";
    cin >> partNumber;

    Tools tool; // create the object

    // user enters information, which is copied into file
    while (partNumber != 0)
    {
        validatePartNumber(partNumber);

        // user enters tool name, quantity and unit price
        cout << "Enter the tool name: ";
        fflush(stdin);
        cin.getline( toolName, 20, '\n' );

        cout << "Enter the quantity in stock: "; 
        cin >> inStock;
        cout << "Enter the unit price: ";
        cin >> unitPrice;

        // set the record for the part number, tool name, quantity in stock, and unit price
        tool.setPartNumber( partNumber );
        tool.setToolName( toolName );
        tool.setInStock( inStock );
        tool.setUnitPrice( unitPrice );

        // seek position in file of user-specified record   
        outTools.seekp( ( tool.getPartNumber() - 1 ) * sizeof ( Tools ) );                         

        // write user-specified information in file                   
        outTools.write( reinterpret_cast < const char * >( &tool ),sizeof ( Tools) );     

        //enable user to enter another account
        cout << "Enter tool identification number (1 to 100, 0 to end input): ";
        cin >> partNumber;

    } // end while loop

} // end enterRecords function

bool Tools::test()
{
   ifstream inTools( "hardware.dat", ios::in | ios::binary );

    // exit program if ifstream cannot open file
    if ( !inTools )
    {
       cerr << "File could not be opened." << endl;
       exit( 1 );
    } // end if

    Tools tool;

    bool answer = false;

    if ( tool.getPartNumber() != 0 )
        answer = true;
    else
        answer = false;

    return answer;
}
void Tools::processChoice()
{
     // open file for reading and writing                                  
     fstream inOutTools( "hardware.dat", ios::in | ios::out | ios::binary );

     // exit program if fstream cannot open file
     if ( !inOutTools )
     {
        cerr << "File could not be opened." << endl;
        exit ( 1 );
     } // end if

    int choice; // store user choice

    // enable user to specify action
    while ( ( choice = enterChoice() ) != END )
    {
        switch ( choice )
        {
           case PRINT: // create text file from record file
              printTextFile( inOutTools );
              break;
           case UPDATE: // update record
              updateRecord( inOutTools );
              break;
           case NEW: // create record
              newRecord( inOutTools );
              break;
           case DELETE: // delete existing record
              deleteRecord( inOutTools );
              break;
          default: // display error if user does not select valid choice
              cerr << "Incorrect choice" << endl;
              break;
        } // end switch

      inOutTools.clear(); // reset end-of-file indicator
    } // end while
}

// enable user to input menu choice
int Tools::enterChoice()
{
     // display available options
     cout << "\nEnter your choice" << endl
        << "1 - store a formatted text file of accounts" << endl
        << "    called \"print.txt\" for printing" << endl
        << "2 - update an account" << endl
        << "3 - add a new account" << endl
        << "4 - delete an account" << endl
        << "5 - end program\n? ";

     int menuChoice;
     //cin >> menuChoice; // input menu selection from user
     menuChoice = 1;
     return menuChoice;
} 

This is how I am calling the functions in main() :

int main()
{
    Tools tool;
    tool.createAndInitializeTextFile();
    tool.enterRecords();
    tool.processChoice();

    if(tool.test())
    {
        "Hardware program successful.";     

    }
    else
    {
        "Hardware program failed.";
    }

    cout << endl;
    return 0;

Edited 3 Years Ago by mike_2000_17: Fixed formatting

Post your enum declaration. I suspect you want something like this:

enum Process(END, PRINT, UPDATE, NEW, DELETE);

which would be the equivalent of

END == 0;
PRINT == 1;
UPDATE == 2;
NEW == 3;
DELETE == 4;

I'm not sure why you have an end program option since you don't include that in the switch. Maybe you wanted this:

PRINT == 1;
UPDATE == 2;
NEW == 3;
DELETE == 4;
END == 5;

which would be this:

enum Process(PRINT = 1, UPDATE, NEW, DELETE, END);

where END ends the switch, not the program.

Post your enum declaration. I suspect you want something like this:

enum Process(END, PRINT, UPDATE, NEW, DELETE);

which would be the equivalent of

END == 0;
PRINT == 1;
UPDATE == 2;
NEW == 3;
DELETE == 4;

I'm not sure why you have an end program option since you don't include that in the switch. Maybe you wanted this:

PRINT == 1;
UPDATE == 2;
NEW == 3;
DELETE == 4;
END == 5;

which would be this:

enum Process(PRINT = 1, UPDATE, NEW, DELETE, END);

where END ends the switch, not the program.

This is what I have in the declaration in the header file:

private:
	enum Choices { PRINT = 1, UPDATE, NEW, DELETE, END };

Maybe there is something wrong in the switch statement?

I know the issue definitely is within the processChoice()function it keeps outputting the request from the enterChoice() function.

I just realized that I had commented out the cin but and had made the choice always to be 1. I did this in order to use a test method.
Do you know which data type is it that every time the call comes back to the function the value of the variable remains the same where it was at last? Const? This way I can use a for next on the variable and only test 1-5 and once 5 occurs the program will terminate and the test function can be successful.

Now my code for the function is the following:

int Tools::enterChoice()
{
     // display available options
     cout << "\nEnter your choice" << endl
        << "1 - store a formatted text file of accounts" << endl
        << "    called \"print.txt\" for printing" << endl
        << "2 - update an account" << endl
        << "3 - add a new account" << endl
        << "4 - delete an account" << endl
        << "5 - end program\n? ";

     int menuChoice;
     cin >> menuChoice; // input menu selection from user
	 //menuChoice = 1;
     return menuChoice;
}

In order to call the functions in the switch as many times as desired I'd use this syntax, because I find it less confusing:

bool anotherChoice = true;
while (anotherChoice)
{
   choice = enterChoice();
   switch ( choice )
   {
      //as you had;
      case END:
         anotherChoice = false;
         break;
   } 
}

If you pass a variable by value to another function then the value of the variable in the calling function won't be modified by the called function. Is that what you mean? If so, I don't see where it applies to the above scenario, unless you do the converse and pass choice by reference to enterChoice(), in which case enterChoice() could be declared with return type void, rather than int.

This article has been dead for over six months. Start a new discussion instead.