问题
I'm new to C and want to write a simple programme to be called with exactly two command line arguments (the first one being the programme's name, the second one being a string). I have validated the number of arguments and now want to validate the input only contains digits.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <cs50.h>
int main(int argc, string argv[])
{
if (argc == 2)
{
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
if isdigit(argv[1][i])
{
printf("Success!\n");
}
else
{
printf("Error. Second argument can be numbers only\n");
return 1;
}
}
else
{
printf("Error. Second argument can be numbers only\n");
return 1;
}
}
While the above code doesn't throw errors, it doesn't correctly validate the input and I can't figure out why. Could someone point me in the right direction?
Thanks a lot in advance and all the best
回答1:
if (argc != 2)
must be
if (argc == 2)
Doing
if isdigit(argv[1][i])
{
printf("Success!\n");
}
you will print "Success" 4 times if the number has 4 digits, better to do something like :
for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
if (!isdigit(argv[1][i])
{
printf("Error. Second argument can be numbers only\n");
return 1;
}
}
printf("Success!\n");
return 0;
Example :
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char * argv[])
{
if (argc == 2)
{
int i, n;
for (i = 0, n = strlen(argv[1]); i < n; i++)
{
if (!isdigit(argv[1][i]))
{
printf("Error. Second argument can be numbers only\n");
return 1;
}
}
printf("Success!\n");
}
else {
puts("argument is missing");
return 1;
}
return 0;
}
Compilation and executions :
pi@raspberrypi:/tmp $ gcc -pedantic -Wextra c.c
pi@raspberrypi:/tmp $ ./a.out
argument is missing
pi@raspberrypi:/tmp $ ./a.out az
Error. Second argument can be numbers only
pi@raspberrypi:/tmp $ ./a.out 12
Success!
pi@raspberrypi:/tmp $ ./a.out 12a
Error. Second argument can be numbers only
pi@raspberrypi:/tmp $
Execution under valgrind :
pi@raspberrypi:/tmp $ valgrind ./a.out 123
==2051== Memcheck, a memory error detector
==2051== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2051== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2051== Command: ./a.out 123
==2051==
Success!
==2051==
==2051== HEAP SUMMARY:
==2051== in use at exit: 0 bytes in 0 blocks
==2051== total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==2051==
==2051== All heap blocks were freed -- no leaks are possible
==2051==
==2051== For counts of detected and suppressed errors, rerun with: -v
==2051== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
回答2:
While you can rely on looping over the characters checking if each isdigit()
, if your purpose is to use the numeric value the argument represents, you may as well use strtol/strtoul
to convert the value to a signed/unsigned
value and rely on the robust error reporting to tell you exactly what occurred during conversion and what, if any, portion of the argument was made up of non-digits.
The strtoX
family of function(s) take a pointer to the string of digits and the address for an endptr
as parameters (as well as the base for integer conversions). The function attempts to convert digits to a number updating endptr
to point to the first character after the last digit successfully converted. This allows you to determine whether your argument was made up of leading digits, whether those fit within the range for the type of conversion attempted, and whether any additional characters exist after the last digit converted.
A short example explains:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <errno.h> /* errno - for strtol validation */
int main (int argc, char **argv) {
char *endptr; /* end pointer for strtol */
long l;
if (argc < 2) { /* validate at least one argument provided */
fprintf (stderr, "error: insufficient arguments provided.\n"
"usage: %s number\n", argv[0]);
return 1;
}
errno = 0; /* zero errno before call */
l = strtol (argv[1], &endptr, 0); /* attempt converstion to long */
if (endptr == argv[1]) { /* check if digits were converted */
fprintf (stderr, "error: no digits converted in '%s'.\n", endptr);
return 1;
}
else if (errno) { /* check for error in conversion */
perror ("strtol-argv[1]");
return 1;
}
printf ("number provided: %ld\n", l); /* output number */
if (*endptr) /* endptr not pointing to `'\0'`, chars remain */
printf ("\nadditional characters following number: '%s'.\n", endptr);
return 0;
}
Example Use/Output
$ ./bin/strtolarg 123456
number provided: 123456
$ ./bin/strtolarg -123456
number provided: -123456
$ ./bin/strtolarg "val=123456"
error: no digits converted in 'val=123456'.
$ ./bin/strtolarg "123456=val"
number provided: 123456
additional characters following number: '=val'.
Look things over and let me know if you have questions.
来源:https://stackoverflow.com/questions/54653523/check-that-command-line-input-is-numeric