r3dux.org

A number-pimping side project from the valleys in *NEW* upside-down flavour.

  • Home
  • ABOUT
  • OLD SITE
  • SEARCH
  • FEEDBACK

How-To: Get valid integer input in C++ (a stupidly long solution to a stupidly simple problem)

r3dux | November 15, 2011

Update: See the comments for a far, far more elegent and robust solution courtesy of the mighty shetboy!


One of the assessments I’ve got my diploma class doing at the moment is to fix all the bugs in some deliberately shonky C++ code. The code just asks for a name (string) and an age in years (int), and it then multiplies the age in years by 365 to give a rough indication of how many days you’ve been alive. So for example if I enter Al and 34 it comes back with:

Hi, Al! You’ve been alive for roughly 12410 days!

The problems come thick and fast though if you want to verify that the age in years entered is really an integer value. You CAN do so like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
using namespace std;
 
int main()
{
    int yearsOld       = 0;
    bool gotValidInput = false;
 
    do
    {
        cout << "Please enter your age in years: ";
        cin >> yearsOld;
 
        if (cin.fail())
        {
            cin.clear();
            cin.ignore();
            cout << "Invalid entry! Whole numbers only, dawg!" << endl;
        }
        else
        {
            // We got some valid input! Set the flag so we can leave the loop!
            gotValidInput = true;
        }
 
    } while ( gotValidInput == false );
 
    cout << "Valid value is: " << yearsOld << endl;
 
    return 0;
}

But you then end up with output like this where each character fails individually:

Please enter your age in years: Mooo...
Invalid entry! Whole numbers only, dawg!
Please enter your age in years: Invalid entry! Whole numbers only, dawg!
Please enter your age in years: Invalid entry! Whole numbers only, dawg!
Please enter your age in years: Invalid entry! Whole numbers only, dawg!
Please enter your age in years: Invalid entry! Whole numbers only, dawg!
Please enter your age in years: Invalid entry! Whole numbers only, dawg!
Please enter your age in years: Invalid entry! Whole numbers only, dawg!
Please enter your age in years:

Obviously that’s no good, so I researched a bit and came up with a solution but –DAMN– it doesn’t feel like the right one… Check out all this clumsiness:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#include <iostream>
#include <sstream>
 
using namespace std;
 
int getValidInteger(string prompt)
{
    bool debug = true;                        // Toggle for verbosity
 
    bool   valid;                             // Our exit flag - we only get out of the do..while loop when this is true
    bool   mixedOperators;                    // Did the user enter a mixture of + and - operators (i.e. -5+3)
    bool   multipleOperators;                 // Did the user enter multiple + or - operators      (i.e. -5-3 or +5+3)
    int    userInt = 0;                       // Integer value we finally return after validation
    string userInput;                         // User input is taken as a string before being wrangled...
    int    foundInvalidInputLocation;         // Character location of any invalid input
 
    string validCharacters  = "+-0123456789"; // All the valid characters we're willing to accept as valid integer input
 
    do
    {
        // Set our initial flags
        valid                     = false;
        mixedOperators            = false;
        multipleOperators         = false;
        foundInvalidInputLocation = 0;
 
        // Display the prompt and get the user input as a string
        cout << endl << prompt << endl;
        getline(cin, userInput);
 
        // Convert the user input string into a input stringstream then...
        istringstream iss(userInput);
 
        // ...try to convert the istringstream into an integer.
        if (iss >> userInt)
        {
            if (debug)
            {
                cout << "This already is or can be made into a valid integer!" << endl;
            }
 
            // Now cast our input string-stream back to a string and...
            string test = iss.str();
 
            // ...test to see if we found any illegal characters (because "123Foo!" -WILL- convert to the int 123, but we want legit input!
            foundInvalidInputLocation = test.find_first_not_of(validCharacters);
 
            if (debug)
            {
                cout << "Value of foundInvalidInputLocation is: " << foundInvalidInputLocation << endl;
            }
 
            // Check whether we found an character which cannot be part of a valid int (-1 indicates no invalid character found)
            if (foundInvalidInputLocation != -1)
            {
                if (debug)
                {
                    cout << "Although we can cast the provided input to an int..." << endl;
                    cout << "...the original input contained at least one invalid character at location: " << foundInvalidInputLocation << endl;
                }
            }
            else // No non-digit characters found? Then we were likely given a legitimate int - but we still need to do more testing to be sure!
            {
                // Find the locations of the first and last plus and minus operators in our converted-from-iss string
                int firstMinusOperatorLoc = test.find_first_of("-");
                int lastMinusOperatorLoc  = test.find_last_of("-");
                int firstPlusOperatorLoc  = test.find_first_of("+");
                int lastPlusOperatorLoc   = test.find_last_of("+");
 
                if (debug)
                {
                    // Wax lyrical about multiple negative operators if detected...
                    cout << "First and last minus signs are at: " << firstMinusOperatorLoc << " and " << lastMinusOperatorLoc << " Match?: ";
                    firstMinusOperatorLoc == lastMinusOperatorLoc? cout << "Yes! This is good!" << endl : cout << "No! Multiple minus operators detected!" << endl;
 
                    // Wax lyrical about multiple positive operators if detected...
                    cout << "First and last plus signs are at: " << firstPlusOperatorLoc << " and " << lastPlusOperatorLoc << " Match?: ";
                    firstPlusOperatorLoc == lastPlusOperatorLoc? cout << "Yes! This is good!" << endl : cout << "No! Multiple plus operators detected!" << endl;
                }
 
                // Got a mixture of both positive and negative operators in the input? Then it's not a valid int!
                if ( (firstMinusOperatorLoc != -1) && (firstPlusOperatorLoc != -1) )
                {
                    if (debug)
                    {
                        cout << "Mixed + and - operators detected, so flagging this as invalid input!" << endl;
                    }
 
                    mixedOperators = true;
                }
                else // No mixed operators? Then we can continue to check for multiple operators...
                {
                    if (debug)
                    {
                        cout << "No mixed operators - continuing... " << endl;
                    }
 
                    // Got multiple negative or positive operators in the input? Then it's not a valid int!
                    if ( (firstMinusOperatorLoc != lastMinusOperatorLoc) || (firstPlusOperatorLoc != lastPlusOperatorLoc) )
                    {
                        if (debug)
                        {
                            cout << "Multiple + or - operators detected, so flagging this as invalid input!" << endl;
                        }
 
                        multipleOperators = true;
                    }
                    else
                    {
                        if (debug)
                        {
                            cout << "No multiple operators - continuing... " << endl;
                        }
                    }
 
                } // End of if mixed operator check else-block
 
                // If we've finally got here and we don't have mixed or multiple operators - then FINALLY we know we have a valid int...
                if ( (mixedOperators == false) && (multipleOperators == false) )
                {
                    if (debug) { cout << "Got a truly valid int! Hurrah!" << endl; }
 
                    // ...so set our exit flag to get out of the do..while loop
                    valid = true;
                }
 
            } // End of if (foundInvalidInputLocation != -1) else section
 
        } // End of if (iss >> userInt) section
        else
        {
            cout << "That's not a valid integer value!" << endl;
        }
 
    } while (valid == false);
 
    // Because we got out of the loop, we must have a valid integer, which we can now return!
    return userInt;
}
 
 
int main()
{
    int x = getValidInteger("Please enter a valid integer: ");
 
    cout << endl << "The value of our valid integer is: " << x << endl;
 
    //system("pause");
    return 0;
}

That works perfectly well as far as I’m concerned (remember – I’m not trying to validate the int to be within a given range or anything – I just want a valid int!) but something is surely wrong here… this should be a one-liner, or maybe three or four lines at the absolute most, not 140 lines or so…

Anyone got any suggestions on how to do this the right way? (In C++ not C, so no atoi or C-strings, and no boost library please! Just “standard” C++!).

Comments
7 Comments »
Categories
Coding
Tags
C++, Input, int, string, stringstream, stupid, user, valid, validate
Comments rss Comments rss
Trackback Trackback

How-To: Fix LMDE Repo Hell

r3dux | November 12, 2011

LMDE is a great distro, but the repo situation is a bit of a mess, what with all the update packs and tracking testing or sid or romeo or wheezy or… yeah, it gets confusing. As I wanted to build openFrameworks the other day and it was moaning about libavcodec and libavcodec-dev mismatches I did a bit of searching around and found this thread over on the mint forums, and making the following changes fixed up the repo issues in no time:

Change your main repos (in /etc/apt/sources.list) to:

deb http://packages.linuxmint.com/ debian main upstream import
deb-src http://packages.linuxmint.com/ debian main upstream import
# deb http://debian.linuxmint.com/incoming testing main contrib non-free
# deb http://debian.linuxmint.com/incoming/security testing/updates main contrib non-free
# deb http://debian.linuxmint.com/incoming/multimedia testing main non-free
 
## DEBIAN
deb http://ftp.us.debian.org/debian/ testing main contrib non-free
deb-src http://ftp.us.debian.org/debian/ testing main contrib non-free
deb http://security.debian.org/ testing/updates main contrib non-free
deb-src http://security.debian.org/ testing/updates main contrib non-free
deb http://www.debian-multimedia.org testing main non-free
deb-src http://www.debian-multimedia.org testing main non-free

Update: Added the deb-src repos to the above list because without them you can’t see package change-logs without ‘em.

And then to ensure the mint repos take precedence over the debian ones, make sure the following is in /etc/apt/preferences:

Package: *
Pin: release o=linuxmint
Pin-Priority: 700
 
Package: *
Pin: origin packages.linuxmint.com
Pin-Priority: 700
 
Package: *
Pin: release o=Debian
Pin-Priority: 500

If you then do and update and upgrade via apt-get or the update manager, all package mismatches should be fixed and you can actually build stuff! Woo! =D

Update May 2012: Getting a large number of packages to be removed when you contemplate updating/upgrading? Pin all repos to 500 (i.e. level the playing field) to fix! Source: http://forum.linuxmint.com/viewtopic.php?f=198&t=67502&p=578038. Thanks, ZeroZero!

Comments
No Comments »
Categories
Coding, How-To, Linux
Tags
Apt, Debian, LMDE, Repo Hell, Repositories, Synaptic, Tracking
Comments rss Comments rss
Trackback Trackback

Chas n’ Dave – Snooker Loopy

r3dux | November 11, 2011

My lovely wife just got me another bouncy-ball for the collection (power-ball, if you’re American), and it’s brown with a monkey face on it. So, as you do, I asked her how many points you score for the brown in snooker – and she hadn’t a clue. So love, this is for you ;)

YouTube Preview Image
Pot the reds then, screw back
for the yellow, green, brown, blue, pink and black!

Funny stuff – hadn’t thought of that in years… Also, quality dubbing! Ha!

Comments
No Comments »
Categories
Humour, Imagery, Life, Music
Tags
80's, Brown, Chas n' Dave, Points, Score, Snooker
Comments rss Comments rss
Trackback Trackback

Skrillex – With You, Friends

r3dux | November 10, 2011

I think Skrillex‘s music is probably a bit marmite (or vegemite, as it is down under), ya know – love it or hate it… Personally, I’m in the love it camp, at least for this track. If you’re interested, the My Name Is Skrillex EP (from which this track comes) is free over on SoundCloud (free SoundCloud account required to DL).

YouTube Preview Image

Also, bonus points for sampling Lemmings Worms =D

Comments
No Comments »
Categories
Music
Tags
My Name Is Skrillex, Skrillex, With You Friends
Comments rss Comments rss
Trackback Trackback

The Shakespeare Insult Kit

r3dux | November 9, 2011

The Shakespeare Insult Kit

Float like a butterfly, sting like a bard =P

Update: Want to automate ye insults? There’s both Java and JavaScript code in the comments! (Thanks, shetboy!)

Comments
6 Comments »
Categories
Humour, Imagery
Tags
Insult, Kit, Shakespeare, Thou
Comments rss Comments rss
Trackback Trackback

« Previous Entries Next Entries »

Translate

Categories

Archives

Tags

3D ActionScript ActionScript 3.0 Adobe AI Ballarat Bash C++ Class Convert CS4 Effect Error Film Flash GLSL Gnome Hack How-To install Jaunty Java Kinect Linkage Linux Mash-Up Microsoft Motion OpenGL Particle Problem PS3 Remix Retro script Slides Sound Systems Texture Ubuntu Video VirtualBox Wii Windows XBox

Gamercard

OpenR3dux

Misc.

Flattr this

RSS Feed

r3dux twitter feed



“Before you judge someone, you should walk a mile in their shoes. That way, when you judge them, you're a mile away and you have their shoes.”

rss Comments rss valid xhtml 1.1 design by jide powered by Wordpress get firefox