Sign in to follow this  

C++, a fresh coat of gloss on my rusty C

This topic is 3660 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

first off, hello gamedev. some years ago, i grabbed myself an 800 page C book and a pirated copy of visual C++ 6. a few months later, i was coding regularly (by my 15-year-old self) and having a wonderful time at it. of course, it didnt take me long to hear all about how C++ was better and i needed to learn it. instead, though, i just kind of stopped coding. haha. its taken me this long (a few days before my 21st birthday) to sit down and finish a C++ book in an attempt to get back into it. now ive got an opengl book, a direct x book, and a intro-level 3d math book waiting for me to get to them with my newfound language. ive decided to undertake a simple console-only project in order to ensure my comfort with C++ before i dove into those more exciting texts, however. it seems that that precaution was well-merited, ha. all im trying to do is write a simple AD&D2E engine demo. character creation, combat, dialog, and a dungeon to crawl. i tried to do this in C so long ago, but it fell on its face because i wanted to make it as robust as morrowind, haha. unfortunately, i got cut short at the beginning. i cant even get a menu working bug-lessly, haha. care to offer some insight?
#include <iostream>
using namespace std;

int main(void)
{
    int menuChoice = 999;

    while(menuChoice != 0)
    {
        cout << "1. Create Character\n";
        cout << "0. Exit\n";

        while(menuChoice < 0 || menuChoice > 1)
        {
            cout << ">>";
            cin >> menuChoice;
            fflush(stdin);
        }

        switch(menuChoice)
        {
            case 0:
                return 0;
                break;

            case 1:
                cout << "\nWoo!\n\n";
                menuChoice = 999;
                break;
			
            default:
                cout << "\nInvalid menu selection, but how did you get here?\n";
                break;
        }
    }
}

fflush(stdin); is an old C habit that ensures things dont go askew. however, it doesnt seem to be helping much. if you compile and run that and input 3498573459087 or something similarly ridiculous (even the word quit works), it explodes. keeps printing >> ad infinitum. someone want to help me make the transition to C++ here? i know i'll have more retarded questions like this. =) thanks guys.

Share this post


Link to post
Share on other sites
debugging with VC++ 2008 express, the value comes out as 999 whether i enter 723948723 or "quit".

then that should be caught by the while loop (obviously is) and brought back to the user input, but it skips it as if it has a carriage return stuck in the instream, which is what fflush(stdin); would solve back in the day for C.

and youd use a string even for a numerical menu?

Share this post


Link to post
Share on other sites
Firstly, try not to mix C functions in with C++ streams. When cin encounters an error extracting the specified type (int here), a few things happen. Obviously, a character or string is not an int (and some huge number such as 7501258152 will not fit into an int data type) so the extraction fails when you enter values like that. The cin stream is then set to a "fail" state, which can be tested for with cin.fail(). Additionally, the data that caused the error is not removed from the stream. This means you need to test the stream state, and reset the stream on bad data, using cin.clear() to reset the fail state and something like cin.ignore() to remove the bad data from the stream.


#include <iostream>
using namespace std;

int main(void)
{
int menuChoice = 999;

while(menuChoice != 0)
{
cout << "1. Create Character\n";
cout << "0. Exit\n";

cout << ">>";
cin >> menuChoice;

while(((menuChoice < 0) || (menuChoice > 1)) || cin.fail())
{
cout << ">>";
cin.clear();
cin.ignore();
cin >> menuChoice;
}

switch(menuChoice)
{
case 0:
return 0;
break;

case 1:
cout << "\nWoo!\n\n";
menuChoice = 999;
break;

default:
cout << "\nInvalid menu selection, but how did you get here?\n";
break;
}
}
}





I've updated your code to illustrate this idea, but you'll probably want to refactor my changes. In any case, running the program now will not result in your infinite loop problem on bad data.

Edit: Actually, there is one more issue with the code I posted. cin.ignore() will remove one character from the cin input stream by default. You can pass in a specified number of characters to remove (such as cin.ignore(2) ). I've updated the code below to remove everything from the input stream on bad input until a newline is reached.


#include <iostream>
#include <limits>
using namespace std;

int main(void)
{
int menuChoice = 999;

while(menuChoice != 0)
{
cout << "1. Create Character\n";
cout << "0. Exit\n";

cout << ">>";
cin >> menuChoice;

while(((menuChoice < 0) || (menuChoice > 1)) || cin.fail())
{
cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n' );

cout << ">>";
cin >> menuChoice;
}

switch(menuChoice)
{
case 0:
return 0;
break;

case 1:
cout << "\nWoo!\n\n";
menuChoice = 999;
break;

default:
cout << "\nInvalid menu selection, but how did you get here?\n";
break;
}
}
}



[Edited by - jcullet on December 5, 2007 2:01:15 PM]

Share this post


Link to post
Share on other sites
awesome! thank you jcullet. =) this is precisely what i need to make a smooth transition to C++, and i really appreciate your taking the time to do that for me.

now, onto the code:

i understand it all, and thats pretty cool. two questions though:

one, is there a streamlined way to do that same thing for string input?

while(((menuChoice != 'y' || menuChoice != 'Y') || (menuChoice != 'n' || menuChoice != 'N')) {...}

or something?

and two, why the super lots of scope? does using std:: when youve declared its namespace as being used help in clarity or something?

Share this post


Link to post
Share on other sites
To answer your question about the using the std:: prefix, I wanted to make it clear that numeric_limits<> and streamsize are found in the standard namespace. Also, I usually do not do a global "using namespace std" in my code, since I find that I tend to get at least a few naming conflicts with my own defined types. For the code here, the std:: prefixes were unnecessary and superfluous. Sorry for the confusion!

Share this post


Link to post
Share on other sites

This topic is 3660 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this