Code Newbie
News     Forums     Search     Members     Sign Up    

My Code Newbie
Username

Password

Articles/Snippets
ASP Classic
ASP.NET
C
C#
C++
HTML / CSS
Java
Javascript
Linux / BSD
Perl
PHP
Python
Ruby
SQL
VB 6
VB.NET

C.N. Friends
  Planet Rome

Link to Us!
Code Newbie
  Code Newbie
    forums
Old 10-16-2004, 07:19 AM   #16 (permalink)
RobertStout
Registered User
 
RobertStout's Avatar
 
Join Date: Oct 2004
Location: Dank cellar
Posts: 18
RobertStout is on a distinguished road
Quote:
perhaps a for(.. ;i < 3; ..) since if suddently someone decides to have I skip two, the != 3 will make it true even when it reaches 23.
I see your point redhead, I got into the habit of using != over > for some reason.
RobertStout is offline   Reply With Quote
Old 10-16-2004, 09:03 AM   #17 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
Quote:
#include <iostream>
#include <string>
using namespace std;
#define RACERS 3
Dont do #define like that.
Since you are using namespace std, we are assuming you are truly programming in standard C++. Don't mix C with C++.
Code this: const unsigned racers = 3;
Also no using of cin.getline() when using std::string. Use std::getline().
__________________
Valmont is offline   Reply With Quote
Old 10-17-2004, 05:34 AM   #18 (permalink)
RobertStout
Registered User
 
RobertStout's Avatar
 
Join Date: Oct 2004
Location: Dank cellar
Posts: 18
RobertStout is on a distinguished road
I have encountered a problem when using std::getline

Here's a snippet..

Code:
/////////////////////////////
// Input name and finish time
for( int i = 0; i < RACERS; i++ )
{
cout << "Enter the name of racer #" << i+1 << ": ";
getline( cin, racers[i].sName );
cout << "Enter the finish time in minutes of racer #" << i+1 << ": ";
cin >> racers[i].iMinutes;
}
Quote:
Console Output..

Race Evaluator

Enter the name of racer #1: John H. Smith
Enter the finish time in minutes of racer #1: 103
Enter the name of racer #2: Enter the finish time in minutes of racer #2:
The problem is highlighted in red above. During the second for pass the program doesn't wait to accept the name input.
After googling my eyes out I can't fix it. Incorrect usage of cin in getline, right? Help would be appreciated.
RobertStout is offline   Reply With Quote
Old 10-17-2004, 09:02 AM   #19 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
After cin>>|anyNUMBER|; the EOF ('n') is left in the stream. So the next call with getline() eats the newline (newline character is by default the EOF for getline()!) and skips the input.

Solution:
Remove the newline before the getline() method is called again.

See my code for the basics. Then see comments after that.
Code:
#include <iostream>
#include <string>
#include <climits>

using namespace std;

//Optional functions: depends on IDE.
void wait_for_enter();

//Additional helper.
void reset_istream( );

//--
const unsigned RACERS = 3;

//The model. Our world.
struct Racer
{
   string sName;
   unsigned nMinutes;
};

int main(int argc, char *argv[])
{
   Racer theRacers[RACERS];
   for( unsigned i = 0; i < RACERS; ++i )
   {
      cout << "Enter the name of racer #" << i+1 << ": ";
      getline( cin, theRacers[i].sName, '\n' );
      cout << "Enter the finish time in minutes of racer #" << i+1 << ": ";
      cin >> theRacers[i].nMinutes;
      reset_istream();
   }
   
   for( unsigned i = 0; i < RACERS; ++i )
      cout<<theRacers[i].sName<<" : "<<theRacers[i].nMinutes<<endl;

   wait_for_enter();
   return 0;
}

//--------------------------------------------------

void reset_istream( )
{
   //Reset failstate just in case.
  cin.clear();
   cin.ignore(numeric_limits<streamsize>::max(), '\n');
}

//---------------------------------------------------

void wait_for_enter()
{
  cout << "press <enter> to continue...\n";
  // Reset failstate, just in case.
  cin.clear();
  string line;
  getline( cin, line);
}
Good.
Now we found out about the basics of emptying the buffer. Also notice that my reset_istream() is programmed differently then then I usually do (see other posts). This method is faster, and proven to be correct in more situations. Both work though. Just a nice heads up. Remember the way I clear the stream well. It is going to be handy in many occasions.

Next thing.
Our input method is basic. A bit too basic for two reasons. Here are the reasons in order of importance:
1) Correctness.
2) Expectations.

Ad 1:
With the std::string, not many things could go wrong. But with the unsgined integer, I could enter a letter or a word or even a sentence for it by accident. The result is undefined then. We have to solve this.

Ad 2:
Once we solved the integer issue, we would like to force the user to really enter a name, and not an empty string (just press enter without entering anything).

I leave one excersise for you though:
Make it also correct when this happens: I enter numbers instead of a words/letters for the name. Don't accept numbers or whatever for my name.

Correctness
The result of entering wrong input into a number variable results in an infinite loop wich is well obvservable in a console application. In that case, the stream enters in a fail state. So one of the things we need to do is resetting the stream state to its initial state: cin.clear();.
The second thing under the hood, is that with the erratic behaviour (infinite loop) an eof is generated. We need to get rid of that end of file character as well: cin.ignore(numeric_limits<streamsize>::max(), '\n');. You will need to include <climits> to make this happen though. What it does is removing everything including the terminating character (eof in our case). It eats up the stream up to the very end.

So here is the complete program where we solved that problem:
Code:
#include <iostream>
#include <string>
#include <climits>

using namespace std;

//Optional functions: depends on IDE.
void wait_for_enter();

//Additional helper.
void reset_istream( );

//The model. Our world.
struct Racer
{
   string sName;
   unsigned nMinutes;
};

//--
const unsigned RACERS = 3;
Racer theRacers[RACERS];

//Core functions.
void menu();
void console_output();

int main(int argc, char *argv[])
{
   menu();
   console_output();
   
   wait_for_enter();
   return 0;
}

//--------------------------------------------------

void menu()
{
   for( unsigned i = 0; i < RACERS; ++i )
   {
      cout << "Enter the name of racer #" << i+1 << ": ";
      getline( cin, theRacers[i].sName);
      cout << "Enter the finish time (minutes) of racer #" << i+1 << ": ";
      while( !(cin >> theRacers[i].nMinutes) )
      {
         cout<<"ERROR! Reason: could not find valid input.\n";
         cout<<"RETRY (finish time in minutes): ";
         reset_istream();
      }
      reset_istream();
   }
}

//--------------------------------------------------

void console_output()
{
   for( unsigned i = 0; i < RACERS; ++i )
   {
      cout<<theRacers[i].sName<<" : "<<theRacers[i].nMinutes<<endl;
   }
}

//--------------------------------------------------

void reset_istream( )
{
   if(cin.eof())
   {
      cin.clear();
   }
   else
   {
      cin.clear();
      cin.ignore(numeric_limits<streamsize>::max(), '\n');
   }
}

//---------------------------------------------------

void wait_for_enter()
{
  cout << "press <enter> to continue...\n";
  // Reset failstate, just in case.
  cin.clear();
  string line;
  getline( cin, line);
}
Expectations
*** to be edited by me in a moment. I want some cappucino first :) ***
__________________

Last edited by Valmont; 10-17-2004 at 10:54 AM.
Valmont is offline   Reply With Quote
Old 10-17-2004, 10:32 AM   #20 (permalink)
RobertStout
Registered User
 
RobertStout's Avatar
 
Join Date: Oct 2004
Location: Dank cellar
Posts: 18
RobertStout is on a distinguished road
Valmont,

Thanks for the comments and suggested exercise.
It is important to me that I learn not only syntax but also the right way to code - so I appreciate the assistance on this front as well.

** I am working on implementing your comments. This post will be modified to include the next version. **
RobertStout is offline   Reply With Quote
Old 10-17-2004, 10:52 AM   #21 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
I've updated my code. You could fix the string problem. But you also could do this - wich is more of stream problem - :
What if I enter (for the time) this: 3.52
We want minutes. So we want whole numbers and whole numbers only as input. If the system doesn't see whole number for minutes, it should be programmed not to accept it.

Make it happen.

In fact. There is a jolly lot left to do. Try to find what I should improve.
__________________
Valmont is offline   Reply With Quote
Old 10-17-2004, 12:58 PM   #22 (permalink)
Valmont
[code][/code] enforcer
 
Valmont's Avatar
 
Join Date: Mar 2003
Location: Netherlands
Posts: 1,545
Valmont is on a distinguished road
To solve the empty-string-puzzle just change menu into this:
Code:
void menu()
{
   string errmsg("ERROR! Reason: could not find valid input.\n");
   for( unsigned i = 0; i < RACERS; ++i )
   {
      cout << "Enter the name of racer #" << i+1 << ": ";
      while( !(getline( cin, theRacers[i].sName)) || theRacers[i].sName.size() == 0 )
      {
         cout<<errmsg;
         cout<<"RETRY (did you enter a name?): ";
         reset_istream();
      }
      cout << "Enter the finish time (minutes) of racer #" << i+1 << ": ";
      while( !(cin >> theRacers[i].nMinutes) )
      {
         cout<<errmsg;
         cout<<"RETRY (finish time in minutes): ";
         reset_istream();
      }
      reset_istream();
   }
}
This code also intercepts input of CTRL-Z/D. That's why the reset_istream() function looks so weird by the way. In this case no terminating character clearance is desired. Otherwise when you try to input a new value, the first terminating character is going to be eaten away.
__________________
Valmont is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On


Similar Threads
Thread Thread Starter Forum Replies Last Post
C++ Deadlock Detection Program Help... coolsc81 Standard C, C++ 2 10-26-2004 06:14 AM
Help on interest program B00tleg Standard C, C++ 2 10-07-2004 08:50 PM
dynamic allocation..urgent help needed!!! kashif Standard C, C++ 4 04-21-2003 08:50 AM


All times are GMT -8. The time now is 08:11 PM.


Powered by vBulletin® Version 3.7.0
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.0.0 RC8





Copyright © 2000-2008, Milano Interactive
Web Hosting provided by Portal 360 Web Hosting