[comp.lang.c] Is There A Way To Check If argv[1] Is An Integer?

eric@ux.acss.umn.edu (Eric D. Hendrickson) (12/16/89)

I need a way to determine if argv[1] (or any argument) is an integer.  How
can this be done?  isdigit(c) will only accept integers, and argv is char.

	Yours,
		-Eric Hendrickson
-- 
/----------"Oh carrots are divine, you get a dozen for dime, its maaaagic."---
|Eric (the "Mentat-Philosopher") Hendrickson	       University of Minnesota
|1 Lind Hall; 207 Church Street S.E.,           Internet: eric@ux.acss.umn.edu
|Minneapolis, MN  55455	  USA	    612/625-0801	    The game is afoot!

poser@csli.Stanford.EDU (Bill Poser) (12/18/89)

In article <984@ux.acss.umn.edu> eric@ux.acss.umn.edu (Eric D. Hendrickson) writes:
>I need a way to determine if argv[1] (or any argument) is an integer.

I use the following procedures to test whether a string is an integer
or a number. They make use of Henry Spencer's regular expression package,
for which you will have to include the declarations.
is_number handles exponential notation, while is_integer does not,
but it should be easy to modify the regular expression. For greater efficiency
you may wish to make these macros and to store the compiled regular
expressions.

int
is_integer(string)
char *string;
{
   return(regexec(regcomp("[-+]?[0-9]+"),string));
}

int
is_number(string)
char *string;
{
   return(regexec(regcomp("[-+]?[0-9]*([0-9]|[0-9]\\.|[0-9]\\.[0-9]|\\.[0-9])[0-9]*([Ee][-+]?[0-9]+)?"),string));
}

(I now await flames on errors in the regular expressions.)

							Bill

davidsen@crdos1.crd.ge.COM (Wm E Davidsen Jr) (12/18/89)

In article <984@ux.acss.umn.edu> eric@ux.acss.umn.edu (Eric D. Hendrickson) writes:
| I need a way to determine if argv[1] (or any argument) is an integer.  How
| can this be done?  isdigit(c) will only accept integers, and argv is char.

  No need to test, argv[1] is char *, never int. It is also not char as
you suggest.

  If you want to determine if an arg starts with a digit, you can do
isdigit(argv[1][0]). If you really want to do it right, you can use:
	int n, m, foo;
	n = sscanf(argv[1], "%d%c", &m, &foo);
	switch (n) {
	case 0: /* no leading digits */
	case 1: /* a valid integer */
	case 2: /* digits with trailing chars */
	}
  In most cases this level of checking is not needed.
-- 
bill davidsen	(davidsen@crdos1.crd.GE.COM -or- uunet!crdgw1!crdos1!davidsen)
"The world is filled with fools. They blindly follow their so-called
'reason' in the face of the church and common sense. Any fool can see
that the world is flat!" - anon

karl@haddock.ima.isc.com (Karl Heuer) (12/21/89)

In article <11467@csli.Stanford.EDU> poser@csli.stanford.edu (Bill Poser) writes:
>In article <984@ux.acss.umn.edu> eric@ux.acss.umn.edu (Eric D. Hendrickson)
>writes the equivalent of:
>int is_integer(char *s) { return(regexec(regcomp("[-+]?[0-9]+"),s)); }

I think regexp is a bit of overkill; I generally use strtol() for this.
(Usually, once you've detected that the argument is in fact an integer, you
need to evaluate it anyway, right?)

And if you're on a backward system that doesn't have strtol(), it's not hard
to write one.  Compared to regexp, for instance.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

kan@dg-rtp.dg.com (Victor Kan) (12/22/89)

In article <15494@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <11467@csli.Stanford.EDU> poser@csli.stanford.edu (Bill Poser) writes:
>>In article <984@ux.acss.umn.edu> eric@ux.acss.umn.edu (Eric D. Hendrickson)
>>writes the equivalent of:
>>int is_integer(char *s) { return(regexec(regcomp("[-+]?[0-9]+"),s)); }
>
>I think regexp is a bit of overkill; I generally use strtol() for this.
>(Usually, once you've detected that the argument is in fact an integer, you
>need to evaluate it anyway, right?)

You could also use sscanf(), although some people like to avoid the
scanf() functions religiously.

Since scanf returns the number of conversions successfully made, it can
serve as an is_integer() function as well as an atoi() type thing.

int
is_integer (s, value)
char *s;
int *value;
{
	/* Add your appropriate NULL checks, etc.
	 */
	return (sscanf (s, "%d", value));
}


>And if you're on a backward system that doesn't have strtol(), it's not hard
>to write one.  Compared to regexp, for instance.

Definitely!  I took a 1.5 credit course (required) called Software Design
Laboratory a few years ago.  We, ten undergrads (mostly runny nosed 
sophomores & juniors), were given an assignment to write an EGREP 
equivalent from scratch in two weeks.  

We weren't allowed to use the system provided re_comp and re_exec 
functions, unless we could magically figure out their inner workings 
without access to source code.  Suffice it to say that even with a 
one week extension, no one in the class finished it, except one really
smart guy who already knew C/Unix before taking the course.

But I digress.

>Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

| Victor Kan               | I speak only for myself.               |  ***
| Data General Corporation | Edito cum Emacs, ergo sum.             | ****
| 62 T.W. Alexander Drive  | Columbia Lions Win, 9 October 1988 for | **** %%%%
| RTP, NC  27709           | a record of 1-44.  Way to go, Lions!   |  *** %%%

tps@chem.ucsd.edu (Tom Stockfisch) (12/22/89)

In article <11467@csli.Stanford.EDU> poser@csli.stanford.edu (Bill Poser) writes:
>In article <984@ux.acss.umn.edu> eric@ux.acss.umn.edu (Eric D. Hendrickson) writes:
>>I need a way to determine if argv[1] (or any argument) is an integer.

>int
>is_integer(string)
>char *string;
>{
>   return(regexec(regcomp("[-+]?[0-9]+"),string));
>}

How about

int	/* really BOOL */
isInteger(string)
	char	*string;
{
	char	*endptr;

	(void)strtol( string, &endptr, 10 );
	return	endptr != string;
}

>(I now await flames on errors in the regular expressions.)
>							Bill

How about flames on requiring unnecessary software?

-- 

|| Tom Stockfisch, UCSD Chemistry	tps@chem.ucsd.edu

meissner@skeptic.osf.org (Michael Meissner) (12/23/89)

In article <636@chem.ucsd.EDU> tps@chem.ucsd.edu (Tom Stockfisch) writes:

	(deleted text asking for a way to determine if argv[x] is a
	number)

>How about
>
>int	/* really BOOL */
>isInteger(string)
>	char	*string;
>{
>	char	*endptr;
>
>	(void)strtol( string, &endptr, 10 );
>	return	endptr != string;
>}

You really should check to see if there is any trailing non-digits, as
well as properly declaring strtol.  Also, you should consider whether
to require the number to be decimal only, or that it can be written in
C notation (decimal, octal, or hex -- I prefer allowing all three):

int	/* really BOOL */
isInteger(string)
	char *string;
{
	extern long strtol();
	char *endptr;

	(void) strtol (string, &endptr, 0);
	return (endptr != string) && (*endptr == '\0');
}

poser@csli.Stanford.EDU (Bill Poser) (12/23/89)

	tps@chem.ucsd.edu (Tom Stockfisch) suggests the following in
place of my regexp based solution:

	int	/* really BOOL */
	isInteger(string)
		char	*string;
	{	
		char	*endptr;
	
		(void)strtol( string, &endptr, 10 );
		return	endptr != string;
	}

and goes on to suggest that the regexp solution involves unnecessary
software.

	One reason not to use this version is because it doesn't
work. Since strtol sets endptr to point to the character that terminated
the scan, it returns true if a non-null prefix of the string is an integer,
which is not the same thing as testing whether the string as a whole
is an integer. To use strtol to do this correctly you have to check
whether endptr is the same as the end of the string.

	Now, if you aren't loading the regexp stuff for any other
purpose, you can keep your code size down a bit by avoiding the use
of regexp. But if you're using regexp anyhow (your interactive program
does have apropos, doesn't it?) it doesn't cost much to use it here.

	The other reason to use the regexp approach is that it makes
it quite simple to implement other predicates. Want to see if the
string is a positive integer? Just get rid of the - in the regular
expression. Want to see if you've got a floating point number in
non-exponential notation? Want to see if you've got a specified number
of digits? These are all easy to do using regular expressions, but
harder to do otherwise. Regular expression techniques provide very
general and flexible solutions to problems of this class. If you really
have a situation in which the overhead is a problem, by all means
use more specialized techniques with lower overhead, but just as it is
foolish to engage in speed optimizations that have little real impact
on performance, so it is foolish to avoid simple general techniques
when it isn't clear that the overhead is significant.

							Bill

tps@chem.ucsd.edu (Tom Stockfisch) (12/29/89)

In article <11523@csli.Stanford.EDU> poser@csli.stanford.edu (Bill Poser) writes:
#	tps@chem.ucsd.edu (Tom Stockfisch) suggests the following in
#place of my regexp based solution:
#	int	/* really BOOL */
#	isInteger(string)
#		char	*string;
#	{	
#		char	*endptr;
#	
#		(void)strtol( string, &endptr, 10 );
#		return	endptr != string;
#	}
#and goes on to suggest that the regexp solution involves unnecessary
#software.
#	One reason not to use this version is because it doesn't
#work. Since strtol sets endptr to point to the character that terminated
#the scan, it returns true if a non-null prefix of the string is an integer,
#which is not the same thing as testing whether the string as a whole
#is an integer.

In the absence of a precise specification, I ignored such subtleties.

#To use strtol to do this correctly you have to check
#whether endptr is the same as the end of the string.

So, add one more test -- don't add all of regexp.

#	The other reason to use the regexp approach is that it makes
#it quite simple to implement other predicates. Want to see if the
#string is a positive integer? Just get rid of the - in the regular
#expression....

In other words, use the most elaborate tool available to solve the
simplest task, in case the task becomes more complicated later?

#	Now, if you aren't loading the regexp stuff for any other
#purpose, you can keep your code size down a bit by avoiding the use
#of regexp.

Its not the overhead that I object to, its having a program unnecessarily
dependend on a non-standard library.

#But if you're using regexp anyhow (your interactive program
#does have apropos, doesn't it?) it doesn't cost much to use it here.

I'll bet the original poster has never heard of regexp, and would have to
be given explicit instructions on how to obtain a copy.
-- 

|| Tom Stockfisch, UCSD Chemistry	tps@chem.ucsd.edu