I tried using the isdigit
function but it only works for chars. I know I can write a function that'll check every char
in a string but is there an already built-in way in c
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Usage: ./caesar key");
return 1;
}
else if (isdigit(argv[1]) != 1)
{
printf("Usage: ./caesar key");
return 1;
}
}
You cannot use isdigit()
to way you do in the question: its argument must be a single character (all values of type unsigned char
) or the special negative value EOF
. Passing a string has undefined behavior.
Your question has many possible answers, depending on what you mean by if a string is a number:
To check if a string pointed to by a pointer s
is composed of digits only using strspn
defined in <string.h>
:
if (*s && s[strspn(s, "0123456789")] == '\0') {
// s is not empty and contains only digits
}
same test using sscanf
defined in `<stdio.h>:
int n = 0;
sscanf(s, "%*[0-9]%n, &n);
if (n > 0 && s[n] == '\0') {
// s is not empty and contains only digits
}
same test using isdigit
defined in `<ctype.h> in a loop:
const char *p = s;
while (isdigit((unsigned char)*p))
p++;
if (p > s && *p == '\0') {
// s is not empty and contains only digits
}
same test, using strtol
defined in <stdlib.h>
. Performs the conversion and accepts optional leading whitespace and an optional sign, may set errno
in case of overflow (errno
is defined in <errno.h>
):
char *p;
long value;
errno = 0;
value = strtol(s, &p, 10);
if (p != s && *p == '\0') {
// s contains the decimal representation of an integer
if (errno) {
// value is too large for type `long`
}
}
Here is an alternative using no library function correctly:
#include <cs50.h>
#include <limits.h>
#include <stdio.h>
enum key_result {
KEY_OK, // string is a valid integer
KEY_TOO_LARGE, // value is outside the range of type `int`
KEY_EMPTY, // string is empty
KEY_NOT_NUMBER, // string does not contain only digits
};
/* parse the argument as a key, store value into `*dest` */
enum key_result get_key(const char *s, int *dest) {
enum key_result res;
int value;
// string must not be empty
if (*s == '\0')
return KEY_EMPTY;
value = 0;
res = KEY_OK;
// consume digits
while (*s >= '0' && *s <= '9') {
int digit = *s++ - '0';
if ((value > INT_MAX / 10)
|| (value == INT_MAX / 10 && digit > INT_MAX % 10)) {
value = INT_MAX;
res = KEY_TOO_LARGE;
} else {
value = value * 10 + digit;
}
}
if (*s != '\0')
return KEY_NOT_NUMBER;
*dest = value;
return res;
}
int main(int argc, char *argv[]) {
int key = 0;
if (argc != 2) {
fprintf(stderr, "Usage: ./caesar key\n");
return 2;
}
switch (get_key(argv[1], &key)) {
case KEY_OK:
printf("caesar: key is %d\n", key);
break;
case KEY_TOO_LARGE:
fprintf(stderr, "caesar: key value is too large: '%s'\n", argv[1]);
return 1;
default:
fprintf(stderr, "caesar: key must be a number\n");
return 1;
}
//...
}