-2

I'm making an app that requires the user to input a production order (7 digits long) like this:

int order = 0;
cout << "Insert the order number: ";
cin >> ordem;

How can I prevent the user from entering a letter? Like "I2345G789"?

Doing that, my app just enters an infinite loop. I was thinking to use a function like this:

bool isLetter(int a)
{
    string s = to_string(a);
    for (int i = 0; i < s.size()-1; i++)
    {
        if (isdigit(s[i]))
        {
            return false;
        }
        else
            return true;
    }       
}

And then:

if (isLetter(order))
{
    cout << "Insert only numbers \n";
}

But it doesn't work. Why? And how can I improve the code?

PS: I'm very new to programming, so, sorry for any beginner mistakes.

honk
  • 9,137
  • 11
  • 75
  • 83
Baron
  • 77
  • 1
  • 1
  • 7
  • possible duplicate of [Good input validation loop using cin - C++](http://stackoverflow.com/questions/2075898/good-input-validation-loop-using-cin-c) – wimh Aug 23 '15 at 08:39
  • 1
    @Wimmel this gives a **different** solution but won't help OP understanding his original mistake. I wouldn't flag this as a duplicate. – Maroun Aug 23 '15 at 08:40
  • Why down vote my question? You guys are too strict c'mon! How can a noob learn that way.. – Baron Aug 23 '15 at 09:25

1 Answers1

2

I guess you have a loop around your code in order to ask for the order number again in case it contains non-digits, for example:

while(...)
{
    int order = 0;
    cout << "Insert the order number: ";
    cin >> order;
}

If you enter something that cannot be parsed into an integer, then the input stream will go into failure mode and that might be the reason why you end up in an infinite loop. In order to overcome your problem in a simple way, you could read a string instead:

string order;
while (true)
{
    cout << "Insert the order number: ";
    cin >> order;

    if (isLetter(order))
        cout << "Insert only numbers" << endl;
    else
        break;
}

The function isLetter() now takes a string and looks like this:

bool isLetter(string s)
{
    // Return true if the given string contains at least one letter.
    for (size_t i = 0; i < s.size(); i++)
        if (!isdigit(s[i]))
            return true;

    // Return false if there are only digits in the given string.
    return false;
}

Please note, that it should be i < s.size() and not i < s.size()-1. And maybe you should rename your function isLetter() to hasLetter(), because that would be a bit more correct.

honk
  • 9,137
  • 11
  • 75
  • 83
  • Good answer! I'm wrong in assuming the `i < s.size() - 1` ?Because in my mind, this would prevent me from getting the final char which would be `'\0'`. – Baron Aug 23 '15 at 09:38
  • The function `size()` excludes `\0` when counting the characters. If a string is `abc`, then its length (size) is 3 and not 4, even if a `\0` is appended in order to properly terminate the string. – honk Aug 23 '15 at 09:42
  • Nice, I didn't knew that. Thank you again! – Baron Aug 23 '15 at 09:47
  • Now i should ask you: Why you used `size_t i` instead of just an `int`? – Baron Aug 23 '15 at 16:27
  • The function `size()` returns the type `size_t`. Nowadays this is usually an unsigned 64-bit integer. If you just use an `int` then your compiler should give you a warning (if you turned warnings on) that you are comparing a signed type to an unsigned type. Also, an `int` usually has only 32 bits. So, for very large structures you could get an overflow. However, an `unsigned int` would also be fine for your use case ;) – honk Aug 23 '15 at 16:40