0

How do I fix this. My program must not accept any alphabet.

Int must accept only valid numbers and reject the string if it contains a alphabet

int main(int argc, char *argv[])
{
    char str[1000];
    int i, ch, key;
    {
        if (argc != 2)
        {
             printf("key\n");
             return 1; // exit prog
        }
        // read argv value into key after argc valid
        //to prevent sementation error
        key = atoi(argv[1]);
        // do multi wrap arounds use leftover digit
        key = (key % 26);
            //check for positive number
        if (key < 1)
        {
        printf("key\n");
        return 1; // exit prog
        }
        // ask for text if pos number
        else if (key >= 0)
        {
        printf("text:");
        // check string and read in
        fgets(str, sizeof str, stdin);
        i = strlen(str);
}

If I type

  • ./name (no input, alphabet, two strings returns 1 as it should.)
  • ./name (number should work and return 0)
  • ./name a1 or b5 return 1 but 1a or 5b return 0 and should not.

In the debugger I can see it only reads the value of the number into argv as 1 or 5 not as 1a or 5b

Cid
  • 14,968
  • 4
  • 30
  • 45
  • First, don't use `atoi()` on unchecked input - it has absolutely no error checking. It returns an `int` no matter what you pass into it, and it has no way of returning an error if the input wasn't a numeric value. – Andrew Henle Aug 03 '20 at 12:37
  • [`isdigit()`](https://linux.die.net/man/3/isdigit) can help – Cid Aug 03 '20 at 12:45
  • Does this answer your question? [How to check if a string is a number?](https://stackoverflow.com/questions/16644906/how-to-check-if-a-string-is-a-number) – Cid Aug 03 '20 at 12:47
  • 1
    @Cid `isdigit()` can be helpful, but your usage is wrong. – MikeCAT Aug 03 '20 at 12:47
  • @MikeCAT oh yeah it takes a single character – Cid Aug 03 '20 at 12:49
  • The "key" must read in the value of argv for an up to int only if the int is valid (2^31). – Johan Maritz Aug 04 '20 at 05:38

3 Answers3

1

Instead of the function atoi use another standard function strtol. For example

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

int main(void) 
{
    const char *s1 = "3g";
    const char *s2 = "32";
    
    char *endptr;

    errno = 0;
    
    long key = strtol( s1, &endptr, 10 );
    if ( *endptr != '\0' || errno != 0 )
    {
        puts( "invalid value supplied" );
    }
    else
    {
        printf( "key = %ld\n", key );
        
    }

    endptr = NULL;
    errno = 0;
    
    key = strtol( s2, &endptr, 10 );
    if ( *endptr != '\0' || errno != 0 )
    {
        puts( "invalid value supplied" );
    }
    else
    {
        printf( "key = %ld\n", key );
        
    }
    
    return 0;
}

The program output is

invalid value supplied
key = 32
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
0

You can use strtol() to convert strings to integers and obtain the last position of converted string.

#include <limits.h>
#include <stdlib.h>
#include <errno.h>

// ...

int key;
// ...
char* end;
long key_temp;
// ...
errno = 0;
key_temp = strtol(argv[1], &end, 10);
if (argv[1][0] == '\0') {
    // no character exists
} else if (*end != '\0') {
    // invalid character exists
} else if ((errno == ERANGE && (key_temp == LONG_MIN || key_temp == LONG_MAX)) ||
key_temp < INT_MIN || INT_MAX < key_temp) {
    // too small or too big
} else if (key_temp == 0 && errno != 0) {
    // other error
} else {
    // looks OK
    key = (int)key_temp;
}
MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • The expression `key_temp < LONG_MIN || LONG_MAX < key_temp` is always false (given the type of `key_temp` is `long`) – M. Nejat Aydin Aug 03 '20 at 13:12
  • @M.NejatAydin Thank you, fixed. – MikeCAT Aug 03 '20 at 13:13
  • Still not guaranteed to work as intended: It might be that `LONG_MIN == INT_MIN` and `LONG_MAX == INT_MAX`. There are some platforms that these are true. The expression will be always false on such platforms. – M. Nejat Aydin Aug 03 '20 at 13:18
  • @M.NejatAydin fixed. – MikeCAT Aug 03 '20 at 13:33
  • `(errno == ERANGE && (key_temp == LONG_MIN || key_temp == LONG_MAX))` is unclear. Why not use `(errno == ERANGE)` instead and skip the `key_temp == ...` tests? – chux - Reinstate Monica Aug 03 '20 at 14:59
  • `else if (key_temp == 0 && errno != 0)` is also unclear. Why not simplify to `else if (errno != 0)`. I see no C spec requiring the return value as 0 on some other error. – chux - Reinstate Monica Aug 03 '20 at 15:01
  • //I did not want to rewrite my code from start so: I added the following into my code just before the "key = atoi(argv[1]);" line else if(strspn(argv[1], "0123456789") == strlen(argv[1])) { } else if(strspn(argv[1], "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./") == strlen(argv[1])) { printf("key\n"); return 1; } – Johan Maritz Aug 04 '20 at 08:56
0
   //I did not want to rewrite my code from start so: I added the following into my 
   //code just before the "key = atoi(argv[1]);" line

                                                                 
     else if(strspn(argv[1], "0123456789") == strlen(argv[1]))
     {
     }   
     else if(strspn(argv[1], "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./") == strlen(argv[1]))
    {  printf("key\n");
        return 1; }