Thread: cin and numbers

  1. #1
    すまん Hikaru's Avatar
    Join Date
    Aug 2006
    Posts
    46

    cin and numbers

    I'm writing a guessing game. The program picks a random number and says whether guesses are less than, greater than, or equal to it. All of that works, but I have two problems.

    First, I want to be able to type q and quit the program, but when I type q, it goes through all of the turns as if I typed the same number. I don't really understand cin good enough to figure out what's going wrong, and I can't find my problem. I think I'm looking for the wrong things.

    Second, the number that the program picks is always the same. I read about rand and srand, and how srand can change the numbers that rand gives, but I can't figure out how to make the number I give srand change without recompiling the program.

    Here's my program.
    Code:
    #include <cstdlib>
    #include <iostream>
    
    using std::cout;
    
    class GuessingGame
    {
    private:
        int rightNumber;
        int turns;
    public:
        enum Result
        {
            LESS,
            EQUAL,
            GREATER
        };
    
        GuessingGame(int low, int high)
        {
            rightNumber = (std::rand() % (high - low)) + low;
            turns = 0;
        }
    
        Result Guess(int guess)
        {
            ++turns;
    
            if (rightNumber < guess)
            {
                return LESS;
            }
            else if (rightNumber > guess)
            {
                return GREATER;
            }
            else
            {
                return EQUAL;
            }
        }
    
        int Turns()
        {
            return turns;
        }
    };
    
    int main()
    {
        const int low = 0;
        const int high = 100;
        const int maxTurns = 10;
    
        GuessingGame game(low, high);
    
        do
        {
            int guess;
            GuessingGame::Result result;
    
            cout << "Pick a number between " << low << " and " << high << "\n";
            std::cin >> guess;
            result = game.Guess(guess);
    
            if (result != GuessingGame::EQUAL)
            {
                int turnsLeft = maxTurns - game.Turns();
    
                if (turnsLeft != 0)
                {
                    if (result == GuessingGame::LESS)
                    {
                        cout << "The number is less than " << guess << "\n";
                    }
                    else
                    {
                        cout << "The number is greater than " << guess << "\n";
                    }
    
                    cout << "You have " << turnsLeft << " turns left\n";
                }
                else
                {
                    cout << "Game over. You have no more turns\n";
                    break;
                }
            }
            else
            {
                cout << "You won! The number was " << guess << "\n";
                break;
            }
        }
        while (true);
    
        return 0;
    }
    Any other suggestions are welcome too. Thanks!

  2. #2
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    For the second, use srand( time(0 ); or something at the start or main (include time, or ctime. I can never remember which). For the first, consult the FAQ I think.

    EDIT - Why do you use cout, and std::cin?
    Last edited by twomers; 08-16-2006 at 05:47 PM.

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    You can use if (!(std::cin >> guess)) to detect when a non-number was entered and quit on that.

  4. #4
    すまん Hikaru's Avatar
    Join Date
    Aug 2006
    Posts
    46
    Quote Originally Posted by twomers
    For the second, use srand( time(0 ); or something at the start or main (include time, or ctime. I can never remember which).
    When I do that the compiler gives me a warning.
    Code:
    warning C4244: 'argument' : conversion from 'time_t' to 'unsigned int', possible loss of data
    I can use a type cast and it goes away, but I read that type casts were bad most of the time. Is this one of the times where it's okay?
    Quote Originally Posted by twomers
    For the first, consult the FAQ I think.
    I'm sorry, I didn't notice that. I'll search there next time before starting a new thread.
    Quote Originally Posted by twomers
    EDIT - Why do you use cout, and std::cin?
    I use cout a lot, but cin once. For things I use more than once I do a using command because typing std:: all the time is tedious.
    Quote Originally Posted by Daved
    You can use if (!(std::cin >> guess)) to detect when a non-number was entered and quit on that.
    Today 07:44 PM
    How does that work?

  5. #5
    The Richness... Richie T's Avatar
    Join Date
    Jan 2006
    Location
    Ireland
    Posts
    469
    >>use srand( time(0 ); or something at the start or main

    yes, and make sure that you only call it once - beginners tend to think they need
    to call srand every time they call rand - which isn't much good. srand is in
    iostream methinks, but you'll need <ctime> to call time (0).

    In reply to your first question, what is happening is a common problem for
    beginners:

    you call cin >> guess;
    guess is defined as type int
    'q' is a char
    cin refuses to read a char into an int variable
    the 'q' character is left in the input buffer
    cin >> guess is called again, and the problem repeats itself.

    Solution? Well it's actually quite straightforward if you're familiar with the
    problem - read the input from the user as a string, and parse it accordingly.
    There are a number of ways to do this, but the C++ way would be to use a
    stringstream - read your value as a string, put it into a stringstream, attempt
    to extract the number, if that fails, attempt to extract the letter, if that fails,
    or if the letter is not 'q', you can prompt user to enter input again or whatever.

    Very basic intro to stringstreams

    Check if a stream failed
    Clear stream error status
    No No's:
    fflush (stdin); gets (); void main ();


    Goodies:
    Example of fgets (); The FAQ, C/C++ Reference


    My Gear:
    OS - Windows XP
    IDE - MS Visual C++ 2008 Express Edition


    ASCII stupid question, get a stupid ANSI

  6. #6
    The superhaterodyne twomers's Avatar
    Join Date
    Dec 2005
    Location
    Ireland
    Posts
    2,273
    My 'FAQ' is a link to a FAQ site regarding this error. Click it, and copy the code, or click this - http://faq.cprogramming.com/cgi-bin/...&id=1043284392

    You can try - http://faq.cprogramming.com/cgi-bin/...&id=1043284385 for random

  7. #7
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> I read that type casts were bad most of the time. Is this one of the times where it's okay?
    Yes.

    >> How does that work?
    operator>> returns the stream, which is converted to a boolean value (true or false). It is false if some error occurred and true if everything was ok. So the if will be entered if the cin >> call returns false so you can quit the program.

    >> srand is in iostream methinks
    <cstdlib>

  8. #8
    The Richness... Richie T's Avatar
    Join Date
    Jan 2006
    Location
    Ireland
    Posts
    469
    >> srand is in iostream methinks
    >><cstdlib>

    That's what I thought too, but this compiles in MSVS C++ Express 2005 - but
    reference says cstdlib as well - non conformance issue!!?

    Code:
    #include <iostream>
    #include <ctime>
    
    int main (void)
    {
    	srand (time (0));
    	std::cout << rand () << std::endl;
    
    	return 0;
    }
    No No's:
    fflush (stdin); gets (); void main ();


    Goodies:
    Example of fgets (); The FAQ, C/C++ Reference


    My Gear:
    OS - Windows XP
    IDE - MS Visual C++ 2008 Express Edition


    ASCII stupid question, get a stupid ANSI

  9. #9
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    The compiler is still conforming. The C++ standard allows standard headers to include parts or all of other standard headers. That's not really a good thing for the programmer, because then you accidentally rely on it and then when you switch to another compiler it just stops working.

  10. #10
    Registered User
    Join Date
    Mar 2006
    Posts
    725
    Always remember: you can do it (eg. srand() inside <iostream>) doesn't mean you should do it. When a reference text says "function foobar() is inside <baz.h>" this means "foobar() is guaranteed to be inside <baz.h>", it doesn't mean "foobar() can only be found inside <baz.h>".

    Suddenly you use a different compiler or a different library set and srand() isn't in <iostream> anymore. Nobody ever said srand() was guaranteed to be in iostream. This can be easily fixed by including <cstdlib>, but imagine if you used 100+ functions which don't belong in <iostream>. You'd go nuts trying to find the correct header files. Better get it right the first time.
    Code:
    #include <stdio.h>
    
    void J(char*a){int f,i=0,c='1';for(;a[i]!='0';++i)if(i==81){
    puts(a);return;}for(;c<='9';++c){for(f=0;f<9;++f)if(a[i-i%27+i%9
    /3*3+f/3*9+f%3]==c||a[i%9+f*9]==c||a[i-i%9+f]==c)goto e;a[i]=c;J(a);a[i]
    ='0';e:;}}int main(int c,char**v){int t=0;if(c>1){for(;v[1][
    t];++t);if(t==81){J(v[1]);return 0;}}puts("sudoku [0-9]{81}");return 1;}

  11. #11
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >>> I read that type casts were bad most of the time. Is this one of the times where it's okay?
    >Yes.
    No. The warning is there for a reason; time_t is not required to be representable by an unsigned integer. While that cast usually works (I have yet to see it fail), the code is inherently non-portable. The only reason it's acceptable is because the idiom is so common, but that doesn't make it correct. A much better solution is to hash the time_t into a suitable unsigned value:
    Code:
    unsigned time_seed()
    {
      time_t now = time ( 0 );
      unsigned char *p = (unsigned char *)&now;
      unsigned seed = 0;
      size_t i;
    
      for ( i = 0; i < sizeof now; i++ )
        seed = seed * ( UCHAR_MAX + 2U ) + p[i];
    
      return seed;
    }
    
    srand ( time_seed() );
    My best code is written with the delete key.

  12. #12
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by Prelude
    No. The warning is there for a reason; time_t is not required to be representable by an unsigned integer.
    But it is required to be an arithmetic type, i.e. either some integer or some floating point number. Arithmetic conversion to all of these is well-defined for the value 0, so the cast is safe. In addition, the C standard itself specifies that time returns (time_t)-1 on error, so it must work.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  13. #13
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >Arithmetic conversion to all of these is well-defined for the value 0, so the cast is safe.
    It's not safe at all. By "arithmetic type", the standard allows time_t to be a floating-point value which could easily be out of range for the largest unsigned integral type. In such a case the rules for unsigned wrapping don't apply and you've invoked undefined behavior because the value being converted cannot be represented by the type being converted to.

    >In addition, the C standard itself specifies that time returns (time_t)-1 on error, so it must work.
    I don't quite follow your logic on this one. Just because (time_t)-1 is required to work doesn't mean that all other operations are also required.
    My best code is written with the delete key.

  14. #14
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by Prelude
    >Arithmetic conversion to all of these is well-defined for the value 0, so the cast is safe.
    It's not safe at all. By "arithmetic type", the standard allows time_t to be a floating-point value which could easily be out of range for the largest unsigned integral type.
    Well possible. But if you read the thing I wrote and you quoted again, you'll find that I only mentioned the value 0.

    (Admittedly, I just realized that only being able to convert 0 doesn't really help, because I confused the parameter to time() and that to srand(). But at least what I wrote was only off-topic, not wrong. )
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  15. #15
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >But if you read the thing I wrote and you quoted again, you'll find that I only mentioned the value 0.
    I know. And I know what you meant too. I thought about pointing it out, but decided against it in favor of attacking the intention of your statement rather than the semantics.

    >But at least what I wrote was only off-topic, not wrong.
    By being off-topic, it was wrong. But I forgive you. Have a cookie for being a good sport.
    My best code is written with the delete key.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. help with c++
    By kbpsu in forum C++ Programming
    Replies: 19
    Last Post: 02-25-2009, 07:36 PM
  2. input with cin....
    By MainFrame in forum C++ Programming
    Replies: 3
    Last Post: 03-19-2004, 06:10 PM
  3. Using really big numbers!
    By Machewy in forum C++ Programming
    Replies: 11
    Last Post: 02-26-2004, 10:49 AM
  4. Cin
    By Blanket in forum C++ Programming
    Replies: 6
    Last Post: 04-15-2003, 08:11 PM
  5. Is cin for only numbers??
    By Carp in forum C++ Programming
    Replies: 16
    Last Post: 01-28-2003, 10:30 PM