4

In college I was asked if our program detects if the string enter from command line arguments is a integer which it did not(./Program 3.7). Now I am wondering how I can detect this. So input as for example a is invalid which atoi detects, but input like for example 3.6 should be invalid but atoi will convert this to an integer.

#include <stdio.h>

int main(int argc, char *argv[]) {
    if (argc > 1) {
        int number = atoi(argv[1]);
        printf("okay\n");
    }
}

But offcourse okay should only be printed if argv[1] is really an integer. Hope my question is clear. Many thanks.

Gregory Pakosz
  • 69,011
  • 20
  • 139
  • 164
Alfred
  • 60,935
  • 33
  • 147
  • 186
  • This is nearly a duplicate of a question asked earlier today. The answer is the same: use strtol. It sets a pointer to the end of what it converted -- if it's anything but '\0', there was something there that couldn't be converted. – Jerry Coffin Jan 08 '10 at 00:13
  • 5
    Is that the faint smell of homework. – Rob Wells Jan 08 '10 at 00:14
  • 1
    would you consider '1e6' an integer? or (perish the thought) '1.234e6' ? Probably best not to go there. – pavium Jan 08 '10 at 00:30
  • @rob: Lol it was homework and it was allready graded (8). I think because of not testing for this I got grade deduction. I just wanted to know the shortest/cleanest. @jerry Which thread was that? – Alfred Jan 08 '10 at 00:39
  • 1
    http://stackoverflow.com/questions/2023079 http://stackoverflow.com/questions/1997587 http://stackoverflow.com/questions/840410 ... – ephemient Jan 08 '10 at 02:27
  • @ephemient, yeah right and a lot of answers advise to use `scanf`... in the end maybe it was a good idea to ask again – Gregory Pakosz Jan 09 '10 at 22:11

4 Answers4

12

Have a look at strtol.

If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, however, strtol() stores the original value of str in *endptr. (Thus, if *str is not \0' but **endptr is \0' on return, the entire string was valid.)

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
  if (argc > 1) {
    char* end;
    long number = strtol(argv[1], &end, 0);
    if (*end == '\0')
      printf("okay\n");
  }
}
Błażej Michalik
  • 4,474
  • 40
  • 55
Gregory Pakosz
  • 69,011
  • 20
  • 139
  • 164
  • I have looked at strtol but i could not implement it to detect 3.6 as invalid input .. – Alfred Jan 08 '10 at 00:17
  • What problems specifically did you have with using `strtol`? Did you check the value to which the pointer points to on return? – Pavel Minaev Jan 08 '10 at 00:29
  • @gregory Thanks gregory. This was exactly what I was looking for and I think the code is pretty dense. @Pavel I think I did not do enough error checking I just did strtol(argv[1], &end, 0); – Alfred Jan 08 '10 at 00:35
2

Assuming you want to know how it could be done in code (possible if it is indeed homework), one way is to think about what constitutes an integer in terms of the string. It would most likely be:

  • an optional sign, +/-.
  • a required digit.
  • any number of optional digits (but watch out for overflow).
  • the end of string.

From that specification, you can write a function that will do the work for you.

Something like this pseudo-code would be a good start:

set sign to +1.
set gotdigit to false.
set accumulator to 0.
set index to 0.
if char[index] is '+':
    set index to index + 1.
else:
    if char[index] is '-':
        set sign to -1.
        set index to index + 1.
while char[index] not end-of-string:
    if char[index] not numeric:
        return error.
    set accumulator to accumulator * 10 + numeric value of char[index].
    catch overflow here and return error.
    set index to index + 1.
    set gotdigit to true.
if not gotdigit:
    return error.
return sign * accumulator.
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
1
int okay = argc>1 && *argv[1];
char* p = argv[1];
int sign = 1;
int value = 0;
if( *p=='-' ) p++, sign=-1;
else if( *p=='+' ) p++;
for( ; *p; p++ ) {
    if( *p>='0' && *p<='9' ) {
        value = 10*value + *p-'0';
    } else {
        okay = 0;
        break;
    }
}
if( okay ) {
    value *= sign;
    printf( "okay, value=%d\n", value );
}

EDIT: allow - and + characters

You may even compress this into a dense one- or two-liner. Or you may find a library function with the same functionality ;)

EDIT2: just for fun - it should now parse the number

Frunsi
  • 7,099
  • 5
  • 36
  • 42
  • see my answer for an `strtol` based implementation, there is no reason to reinvent the (square) wheel :) – Gregory Pakosz Jan 08 '10 at 00:27
  • Hehe I tested this code but it does not work. First off all because false is not really part of c. But I think you are in the right direction ;). It will also throw segmentation fault when no arguments are supplied. – Alfred Jan 08 '10 at 00:27
  • @Carl: d'oh, will change it..., @Alfred: Again, d'oh – Frunsi Jan 08 '10 at 00:31
  • @Frunsi I guess that would be a smart thing to do because right now this code will blow up in your face (so please update code to be correct for other stackoverflow members). – Alfred Jan 08 '10 at 00:41
  • LOL, I'll give +1 for the `strtol` solution. I just tried a quick&dirty approach, and the current one should even work. Also note: its a fragment, no function, no program, so a check for valid number of arguments is still required. – Frunsi Jan 08 '10 at 00:52
  • Okay because when you compile this code and do not provide arguments this program will give a segmentation fault. – Alfred Jan 08 '10 at 01:48
  • Thou shalt not blindly copy, paste & execute any source code. – Frunsi Jan 08 '10 at 02:13
1

So your best choice is strtof() http://publib.boulder.ibm.com/infocenter/zos/v1r10/topic/com.ibm.zos.r10.bpxbd00/strtof.htm

alemjerus
  • 8,023
  • 3
  • 32
  • 40