Thread: cin not allowing input after first use of function

  1. #1
    Registered User
    Join Date
    Jan 2006
    Location
    Seattle
    Posts
    30

    cin not allowing input after first use of function

    Hi,

    I've been searching around the internet for an answer to my problem for a little bit now but haven't been able to find anything. This being my first big C++ project I've been running in to lots of trouble, most notably with the inability to take input from a cin statement the second time I call one of my functions. The first time through the function everything works as it should but the second time through the cout text is output put cin acts as if the user has already typed in something (although when using my VS 2003 .net debugger I can see that the values remain at 0). Any help would be greatly appreciated.

    The file in question contains 3 functions so I'll truncated it down to the one I'm having problems with. The problems are occurring directly at the begining of the file with the cin statements but I included the whole thing just to make sure although I'm doubting there's anything wrong (at least with regards to the cin statements) at the end of the file.

    Thanks for any help anyone can bestow upon me.

    PHP Code:
    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    #include "Structures.h"

    using namespace std;

    int CreateUnit()
    {
        
    // String input code referenced to test code created by Justin Biller

        // ********* So many errors occur with the error checking, I've been messing with it for a while but I don't
        // understand what's going on half of the time.

        
    char input[5], delimiters[4] = { '-'' '','};
        
    char *tokenOne, *tokenTwo, *point ;
        
    char CUnit 0;
        
    int CreateX 0CreateY 0Team 0;
        
    int pause 0;

        
    cout << "Enter unit team (1 or 2): ";
        
    cin  >> Team;

        
    Team Team << 7;

        
    cout << "Enter unit to be created: ";
        
    cin  >> CUnit;

        if(
    CUnit 96)            // if character selection is lower case converts to uppercase so it only checks
            
    CUnit -= 32;        // one value during the switch statement, needs error checking for invalid input

        
    if((CUnit == 'I' || CUnit == 'F' || CUnit == 'R' || CUnit == 'B' || CUnit == 'T' || CUnit == 'A' || 
            
    CUnit == 'H' || CUnit == 'J' || CUnit == 'N' || CUnit == 'S' || CUnit == 'V') != 1)
        {
            
    cout << "Ivalid input" << endl;
            
    CreateUnit();
        }

        
    /* Will take in a string, seperate it into two variables, then set those
        variables equal to numbers that can be used for settings in an array.*/

        
    cout << "Enter position of created unit (Y,X)(Y-X)(Y X): ";
        
    cin  >> pause;            // *************** I don't know why this works, more testing to be done tomorrow
        
    gets(input);            // without it "gets" will not work ********************************************* 

        
    if(pause != 0)
        {
            
    cout << "Ivalid input" << endl;
            
    CreateUnit();
        }
        
        
    tokenOne strtok(inputdelimiters);
        
    tokenTwo strtok(NULLdelimiters);

        if(*
    tokenOne <= 85)        // converts to array equivilent of the ASCII letter (IE A converted to 0 for position 1)
            
    CreateY = *tokenOne 65;
        else
            
    CreateY = *tokenOne 97;

        
    /* I use strtod here to take out the int from tokentwo.  Using strtod on the
        pointer allows us to remove the actual number and place it into an int.  Other-
        wise you would be stuck just trying to use the first digit of the number since
        strtok sets each char in the string to one digit, so if tokentwo took in '10'
        you would only have access to the number '1' since the '1' and the '0' are in
        their own section of memory of the array.  These can be printed with %s, but
        you can't actually use the value itself. */

        
    CreateX strtod(tokenTwo, &point);
        
    CreateX--;

        if (
    CreateY || CreateY 19 || CreateX || CreateX 19)    // ****************************
        
    {                                                                // THESE VALUES WILL NEED TO BE 
            
    cout << "Ivalid input" << endl;                                // REPLACED BY THE GRID VALUES
            
    CreateUnit();                                                // ****************************
        
    }

        
    //*********************************************************************************************
            
        
    Infrant.HP=5;            // Health values for every unit
        
    Flame.HP=5
        
    Rocket.HP=6
        
    ABuggy.HP=10
        
    Tank.HP=20
        
    Art.HP=10
        
    AHeli.HP=8
        
    Jet.HP=12
        
    Bomber.HP=15
        
    SInfran.HP=5
        
    SBuggy.HP=8

        switch ( 
    CUnit )
        {
        case 
    'I' :            // Infantry
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = Infrant.HP Team;
                break;
            }
        case 
    'F' :            // Flame Infantry
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = Flame.HP Team;
                break;
            }
        case 
    'R' :            // Rocket Infantry
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = Rocket.HP Team;
                break;
            }
        case 
    'B' :            // Buggy
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = ABuggy.HP Team;
                break;
            }
        case 
    'T' :            // Tank
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = Tank.HP Team;
                break;
            }
        case 
    'A' :            // Artillery
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = Art.HP Team;
                break;
            }
        case 
    'H' :            // Attack Helicopter
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = AHeli.HP Team;
                break;
            }
        case 
    'J' :            // Jet
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = Jet.HP Team;
                break;
            }
        case 
    'N' :            // Bomber
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = Bomber.HP Team;
                break;
            }
        case 
    'S' :            // Spy Infantry
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = SInfran.HP Team;
                break;
            }
        case 
    'V' :            // Spy Buggy
            
    {
                array[
    CreateX][CreateY] = CUnit;
                
    HealthArray[CreateX][CreateY] = SBuggy.HP Team;
                break;
            }
        }
        
        return 
    0;

    Remember I'm able to compile the code and run it once just fine, just those first cins asking for team, unit, and position are giving me problems. Mucho frustrating.

    -Peter

    ***edit***

    I forgot to mention... all I recieve as output the second time through the function is a constant barrage of error messages. The "error testing" picks up a bad input somewhere and because cin isn't working the cycle repeats ad infinatum until I close my program. Oh... and I'm compiling in Visual Studio 2003 .net
    Last edited by Peter5897; 01-31-2006 at 01:55 AM.

  2. #2
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    Note: gets() is a C function. getline() is the C++ way.

    A line like this:

    cin >>num

    waits for the user to enter some input. Then the user can type something in and hit Return. However, when the user hits Return, an invisible \n or "newline" character is entered after the input ('\n' is considered a single character). So, if the user types in 10 and hits Return, the input actually looks like this:

    10\n

    Now, let's examine how that input is handled. The >> operator is programmed to skip all leading whitespace(e.g. spaces, tabs, and newlines), then read in data, and finally stop reading in data when the first white space character is encountered. And, very importantly, the terminating whitespace character is not read in. So, with this input:

    10\n

    1) cin>> skips any leading whitespace(in this case there's no whitespace in front of 10)
    2) cin>> reads in 10, and
    3) cin>> stops reading when it encounters the whitespace character \n
    4) cin>> does not read in the \n, and leaves the \n in the input stream.

    Sometime thereafter, if these lines are executed:

    cout << "\nEnter your name: ";
    getline(cin, name);

    then that is an instruction to read in more input. Specifically, getline() grabs all the input it can including whitespace until it hits the end of the line, which is indicated by a newline character '\n'. Very importantly, unlike the >>operator, getline() reads in the \n character at the end of the line--thereby removing it from the stream--and discards it. In your case, there is still a \n left in the input stream, and as far as getline() is concerned that is good input, so it doesn't need to wait for any user input, and therefore getline() does its thing and reads in the \n.

    The lesson is: if you are going to be switching between the >>operator and getline(), you need to remove the '\n' character that is inserted at the end of the input when the user hits Return. You can remove a trailing whitespace character like this:

    cin>>data;
    cin.ignore(1);

    cin.ignore() will remove the designated number of characters from the stream.

    Note that cin.ignore() is not necessary when you do something like this:

    cin>>data;

    and then the user enters:

    10\n

    and then you do something like this:

    cin>>data2;

    Since the >> operator skips leading whitespace, it skips over the \n remaining in the stream and searches for some input, and when it can't find any, it stops and waits for the user to enter something.
    -----

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <math.h>
    In C++, no legal header file names end in ".h". Those should be cstdio, cstdlib, cstring, and cmath respectively.
    ---

    Also, in C++ we use the <string> type for strings instead of char arrays. string types can be added together with a + sign, and are generally much easier to use than char arrays.
    Last edited by 7stud; 01-31-2006 at 02:34 AM.

  3. #3
    Registered User
    Join Date
    Jan 2006
    Location
    Seattle
    Posts
    30
    Thank you very much 7stud, worked like a charm. I was also able to get rid of my little "cin >> pause" that I was using as a means to get meaningful input into my "gets" statement.

    Another question though... do those headers you mentioned contain the same information as the ones I'm using already? This is my first full year programing and I've only "learned" C thusfur and I'm taking C++ concurrently. Do I lose anything if I go with cmath as opposed to math.h? I'll try throwing them in there but I just want to make sure that it's not going to create problems down the line if I'm trying to write some of my code in C.

    Thanks again!

    -Peter

    ***Edit****

    Never mind about the header question... once I started typing them in I figured it out after typing in the "c" in front of all my previous #includes
    Last edited by Peter5897; 01-31-2006 at 10:10 AM.

  4. #4
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    In C++, no legal header file names end in ".h".
    ->
    Code:
    In C++, no [standard] header file names end in ".h".
    You can still call your header files header.h, and many people do.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  5. #5
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    FAQ on flushing the input buffer: http://faq.cprogramming.com/cgi-bin/...&id=1043284392

    You might want to use whatever the C++ equivalent of clearerr(stdin) is, too.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    >> In C++, no [standard] header file names end in ".h".

    This is also wrong. The headers used in the original program were all standard C++ header files (except of course Structures.h). The ones with the .h in the above example are from the C library, and they are allowed to have the .h. However, the use of the C version of the headers is deprecated, which means that it is standard but it might be removed from the standard in the future.

    Basically, you should use the versions without the .h (<cstdio>, <cmath>, etc.), but for the C library headers it will still work on standards compliant compilers if you use the C way. The only difference between the versions is the use of the std namespace in the C++ version.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 28
    Last Post: 07-16-2006, 11:35 PM
  2. Calling a Thread with a Function Pointer.
    By ScrollMaster in forum Windows Programming
    Replies: 6
    Last Post: 06-10-2006, 08:56 AM
  3. Dikumud
    By maxorator in forum C++ Programming
    Replies: 1
    Last Post: 10-01-2005, 06:39 AM
  4. Contest Results - May 27, 2002
    By ygfperson in forum A Brief History of Cprogramming.com
    Replies: 18
    Last Post: 06-18-2002, 01:27 PM