0

Which way is better to identify a digit? I'm analyzing a 9 digit array of integers to test whether they are all between 0-9 inclusive.

for (i = 0; i < 9; i++) {
    if (str[i] < 48 || str[i] > 57) {
        cout >> "failed" >> endl;
    }
    else {
        cout >> "passed" >> endl;
    }
}  


for (i = 0; i < 9; i++) {
    if (str[i] < '0' || str[i] > '9') {
        cout >> "failed" >> endl;
    }
    else {
        cout >> "passed" >> endl;
    }
}
eveo
  • 2,797
  • 15
  • 61
  • 95
  • The latter one will work when ASCII isn't in use. – chris Jan 27 '13 at 18:21
  • What do you mean when "ASCII isn't in use"? – eveo Jan 27 '13 at 18:31
  • ASCII is one character set and the most common one. In ASCII, '0' is 48 and 'A' is 65. It's not guaranteed to be in use, however, so in your code, 'A' could actually be 25, or whatever the character set in use defines it as. The [Wikipedia](http://en.wikipedia.org/wiki/ASCII) article might help a bit. – chris Jan 27 '13 at 18:36
  • 3
    Besides portablility, which, realistically, isn't much of an issue in this case, the second is much more comprehensible, especially to someone who doesn't have the ASCII table memorized. The first one should have a comment, the second is self-documenting. – Benjamin Lindley Jan 27 '13 at 18:37
  • Thanks guys, cleared it up. – eveo Jan 27 '13 at 18:40

2 Answers2

4

You can just use isdigit.

Your second option also works. The first one doesn't have to, because '0' doesn't necessarily have to correspond to 48. The values are guaranteed to be consecutive, but they don't have to start at 48 (although they likely do).

Community
  • 1
  • 1
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
4

I would use std::all_of in combination with a predicate (better if a short, terse lambda) that uses std::isdigit():

bool ok = std::all_of(begin(str), end(str), [] (char c) { return std::isdigit(c); });

This allows you to test any sub-range you wish, and the iteration cycle comes for free.

You have to include the <cctype> header (for std::isdigit()) and the <algorithm> header (for std::all_of).

EDIT:

If you do not want to use a lambda, you can even pass in the std::digit function directly, if you provide a proper cast (see this Q&A for an explanation):

bool ok = std::all_of(begin(str), end(str), (int (*)(int))std::isdigit);

The cast is necessary because in the std namespace, there are overloads of isdigit which is causing problem in overload resolution. The other topic discusses a similar case in a bit detail.

Or if that looks cumbersome, you can do this instead:

int (*predicate)(int) = std::isdigit;
bool ok = std::all_of(begin(str), end(str), predicate);

That should work fine!

Community
  • 1
  • 1
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • @AndyProwl: Why even lambda? You can pass `std::isdigit` itself as third argument : `std::all_of(begin(str), end(str), std::isdigit);`. Can't you? – Nawaz Jan 27 '13 at 18:32
  • That's a fantastic example but I'm afraid I can't use that as this is a basic C++ course designed to do things the hard way so you can understand the internals of the language. – eveo Jan 27 '13 at 18:32
  • @Nawaz: well, that's what I thought, then I tried it and it didn't work... so I thought I'd figure out why first – Andy Prowl Jan 27 '13 at 18:33
  • @eveo: I understand. In that case, I'd go for the second alternative you propose. The first one is not portable (see answer by @LuchianGrigore) – Andy Prowl Jan 27 '13 at 18:34
  • @AndyProwl: What is the error? You probably need to cast into the proper type. there may be overloads which create problem : See this : [std::transform() and toupper(), no matching function](http://stackoverflow.com/questions/7131858/stdtransform-and-toupper-no-matching-function). The same probably is true of `std::digit` also? – Nawaz Jan 27 '13 at 18:36
  • @AndyProwl: Yes, it is exactly the [same problem](http://stacked-crooked.com/view?id=4038c11671a5acbc1ab436db0af95452). Once it cast [it works great!](http://stacked-crooked.com/view?id=5d4f6830ff5cc2015985e57aa1ab69f9) – Nawaz Jan 27 '13 at 18:43
  • Personally, I prefer the lambda. The cast is ugly and syntactically error prone. – Benjamin Lindley Jan 27 '13 at 18:43
  • [Even this works without cast](http://stacked-crooked.com/view?id=28cdf8273f0d0d443168e5dc7dd9507e), though not sure if the existence of `::isdigit` is guaranteed by the Standard. – Nawaz Jan 27 '13 at 19:02
  • @Nawaz: 17.6.1.1/2 says: "All library entities except macros, operator new and operator delete are defined within the namespace `std` or namespaces nested within namespace `std`". So I guess that's not portable – Andy Prowl Jan 27 '13 at 19:12