0

I'm trying to get an integer number from command line without scanf() but using justfgets(), how can I filter the fgets() contentsreporting an error if I insert a character or a string? The problem is that when I insert something different like a character or a string the atoi()function (essential to do some operations in my algorithm) converts me that string to 0, whilst I'd prefer to exit if the value inserted is different from an integer. Here's a code part:

.....
char pos[30];
printf("\n Insert a number: ");
fgets (pos, sizeof(pos), stdin);
if (atoi(pos) < 0) //missing check for string character
    exit(1);
else{
printf ("%d\n", atoi(pos)); //a string or character converted through atoi() gives 0
}
int number = atoi(pos);
......
Cœur
  • 37,241
  • 25
  • 195
  • 267
Mark
  • 13
  • 7
  • 4
    using something like [`strtol`](https://linux.die.net/man/3/strtol) is preferred because of the error checking. – yano Feb 11 '20 at 00:28
  • 4
    Don't use `atoi`. Use `sscanf` and check the return value, or use `strtol` and [see this question](https://stackoverflow.com/questions/36074422). – user3386109 Feb 11 '20 at 00:30
  • [Why shouldn't I use atoi()?](https://stackoverflow.com/q/17710018/995714) – phuclv Feb 11 '20 at 03:12

3 Answers3

2

As commenters have said, use strtol() not atoi().

The problem with strtol() is that it will only give an ERANGE error (as per the specification) when the converted number will not fit in a long-type. So if you ask it to convert " 1" it gives 1. If you ask it to convert "apple", it returns 0 and sets endptr to indicate an error.

Obviously you need to decide if " 12" is going to be acceptable input or not — strtol() will happily skip the leading white space.

EDIT: Function updated to better handle errors via the endptr.

// Convert the given <text> string to a decimal long, in <value>
// Allow a string of digits, or white space then digits
// returns 1 for OK, or 0 otherwise
int parseLong( const char *text, long *value )
{
    int rc = 0;    // fail
    char *endptr;  // used to determine failure

    if ( text && value )
    {
        errno = 0;                               // Clear any errors
        *value = strtol( text, &endptr, 10 );    // Do the conversion

        // Check that conversion was performed, and
        // that the value fits in a long
        if ( endptr != text && errno != ERANGE ) 
        {
            rc = 1;  // success
        }
    }

    return rc;
}
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Kingsley
  • 14,398
  • 5
  • 31
  • 53
  • 1
    It is an error if you type `Apple` and don’t allow hex. And `strtol()` tells you if you pay attention, but the report is subtle. In particular, you can’t use NULL for the second argument as that’s what is used to report conversion failure. – Jonathan Leffler Feb 11 '20 at 00:58
  • Note [Correct usage of `strtol()`](https://stackoverflow.com/a/14176593/15168). – Jonathan Leffler Feb 11 '20 at 01:16
  • @JonathanLeffler - thanks for the heads-up on `endptr`, I edited the answer. – Kingsley Feb 11 '20 at 02:13
  • Do you want to discuss checking whether what follows is permissible? For example, trailing white space might be fine, but any other character (e.g. a letter or punctuation such as a dot) might be inadmissible. Now you've got `endptr`, you can tell where the conversion ended and check whether the characters after what was converted were allowable. – Jonathan Leffler Feb 11 '20 at 02:29
0

First, you have to keep in mind that characters are not essentially alpha characters; be precise.

I think what you're looking for is an "is integer" function. In the standard C library ctype.h there are functions called isalpha and isdigit.

https://www.programiz.com/c-programming/library-function/ctype.h/isalpha

So you could make a function that verifies if a char * contains only numeric characters.

int str_is_only_numeric(const char *str) {
    int i = 0;
    while (str[i] != '\0') {
        if (isdigit(str[i++]) == 0) {
            return -1;
        }
    }
    return 0;
} 

Here's a working example of the function: https://onlinegdb.com/SJBdLdy78

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Benjamin Audet
  • 463
  • 3
  • 12
  • 3
    This ignores the possibility of `+, -` and leading/trailing white-space. – chux - Reinstate Monica Feb 11 '20 at 00:49
  • But it doesn't work if I insert a number into my buffer, it returns -1 anyway: int check_int (char s[], int n){ int i = 0; while (s[i] != '\0'){ if (isdigit (s[i++]) == 0) return -1; } return 0; } – Mark Feb 11 '20 at 13:56
0

I solved on my own using strcspn()before checking through isdigit()the integer type, without strcspn() it'd have returned always -1

Mark
  • 13
  • 7