Thread: help with a function that determins digit or not digit needed, apply within.

  1. #1
    Banned
    Join Date
    Aug 2017
    Posts
    861

    Talking help with a function that determins digit or not digit needed, apply within.

    function: reads in data type char, runs through it, if it finds a non digit within the string, return -1 to indicate error, else return its value as an int.

    this only works up to a point,then fails. theoretically it is not suppose to be happening. But that is theory for ya.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <string.h>
    #include "data.h"
    
    int int_or_ch(char *data)
    {
        int len = 0, i;
        char str1[1+strlen(data)];
        char *ptr;
        strcpy(str1, data);
    
        len = strlen(str1);
        ptr = str1;
    
    printf("got length %dand input is %s\n", len, str1);
        for ( i = 0; i < len - 1; i++)
        {
            printf("%c\n", ptr[i]);
            // if not a digit return error code -1
            if ( isdigit(ptr[i]) == 0)
                return -1;
         }
         return atoi(str1);
     }
    input, if I input 15 chars I get this:
    Code:
    userx@slackwhere:~/bin/
    $ ./a.out
    input a number
    123456789012345
    got length 16and input is 123456789012345
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    0
    1
    2
    3
    4
    5
    you entered -2045911175
    if Iinput 20 chars , 1 - 9 +0 twice, by just running my finger across the numbers on the keyboard, I get a -1 returned. but I get all of the numbers I put into the string print out from the function just prior to isdigit looking at it.

    SO I am missing something here and I do not know what that is.

    I am going to go look into return types int maybe too short that maybe why I am getting a negative number returned. .


    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #include "data.h"
    
    int main (void)
    {
        char *buffer = NULL;
        size_t len;
        int flag = 0;
        int results = 0;
        printf("input a number\n");
    
        while ( flag != 1 )
        {
            getline(&buffer, &len, stdin);
            results =  int_or_ch(buffer);
    
            if (results == -1)
                    printf("reenter a number\n");
                else
                {
                    printf("you entered %d\n", results);
                    flag = 1;
                }
            }
            free(buffer);
    return 0;
    }
    a good output if not all digits. because it returns -1 on first non - digit
    Code:
    userx@slackwhere:~/bin/
    $ ./a.out
    input a number
    23de
    got length 5and input is 23de
    
    2
    3
    d
    reenter a number
    side bar:
    I still do not have a handle on debugger, that is why I use printf, but, I'd like
    to get a quick study instructions on what exactly do I got to write to get it to
    go into the files it needs to. this particular function is in a file called, data.c


    Code:
    List of classes of commands:
    
    aliases -- Aliases of other commands
    breakpoints -- Making program stop at certain points
    data -- Examining data
    files -- Specifying and examining files
    internals -- Maintenance commands
    obscure -- Obscure features
    running -- Running the program
    stack -- Examining the stack
    status -- Status inquiries
    support -- Support facilities
    tracepoints -- Tracing of program execution without stopping the program
    user-defined -- User-defined commands
    
    ---Type <return> to continue, or q <return> to quit---
    Type "help" followed by a class name for a list of commands in that class.
    Type "help all" for the list of all commands.
    Type "help" followed by command name for full documentation.
    Type "apropos word" to search for commands related to "word".
    Command name abbreviations are allowed if unambiguous.
    (gdb) files data.c
    Undefined
    Last edited by userxbw; 10-20-2017 at 08:02 AM.

  2. #2
    Banned
    Join Date
    Aug 2017
    Posts
    861
    I think it is just going out of range so rather than ... just put a check in it if over x=N digits return an out of range error code. as I've fiddled with it using
    strtol and strtoll . unless someone else can come up with a solution.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <string.h>
    #include "data.h"
    
    int int_or_ch(char *data)
    {
        int len = 0, i, base;
        char str1[1+strlen(data)];
        char *ptr, *endptr;
        strcpy(str1, data);
    
        len = strlen(str1);
        ptr = str1;
    
    printf("got length %dand input is %s\n", len, str1);
    //    if (len > 11 )
        //S    return -2;
    
        for ( i = 0; i < len - 1; i++)
        {
            printf("%c\n", ptr[i]);
            // if not a digit return error code -1
            if ( isdigit(ptr[i]) == 0)
                return -1;
         }
         base = (len > 11) ? atoi(str1) : 10;
         printf("base %d\n", base);
    
         return strtoll(str1, &endptr, base);
     }
    Code:
    userx@slackwhere:~/bin/calculator
    $ ./a.out
    input a number
    123456789012345
    got length 16and input is 123456789012345
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    0
    1
    2
    3
    4
    5
    base -2045911175
    you entered 0
    because anything over 10 digits it returns negative numbers. but, as stated, out of curiosity, and if it can be done, . unless someone else can come up with a solution that knows more about this then I do ( at this moment in time). I am open to hearing it.

    going to go look into base numbers, because I need to check into that trinity operator 's else statement of 10
    Last edited by userxbw; 10-20-2017 at 08:16 AM.

  3. #3
    Banned
    Join Date
    Aug 2017
    Posts
    861
    Ok I got it,
    I've never dealt with anything over an int - for formatting printf for long, return value I needed to change for long, and well its in the code. not cleaned up to show work ... and what I used to help me figure it out.

    I was fiddling with the code so much I forgot about my return value,

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <string.h>
    
    #include <errno.h>
    #include <limits.h>
    
    #include "data.h"
    
    long int_or_ch(char *data)
    {
        int len = 0, i, base;
        char str1[1+strlen(data)];
        char *ptr, *endptr;
        long val = 0;
        strcpy(str1, data);
    
        len = strlen(str1);
        ptr = str1;
        printf("ptr %s\n", ptr);
    
    printf("\ngot length %dand input is %s\n", len, str1);
    //    if (len > 11 )
        //    return -2;
    
        for ( i = 0; i < len - 1; i++)
        {
            printf("%c\n", ptr[i]);
            // if not a digit return error code -1
            if ( isdigit(ptr[i]) == 0)
                return -1;
         }
         printf(" 2 ptr %s\n", ptr);
     //     base = (len > 11) ? atoi(str1) : 10;
        // printf("base %d\n", base);
         base = 10;
            val = strtol(ptr, &endptr, base);
            printf("#@# val = %li\n",val);
         return val;
     }
    
    void using_strtoll(int argc, char **argv)
    {
        int base;
        char *endptr, *str;
        long val;
    
        if (argc < 2) {
            fprintf(stderr, "Usage: %s str [base]\n", argv[0]);
            exit(EXIT_FAILURE);
        }
        printf(" argv[1] %s\n",  argv[1]);
        str = argv[1];
        printf(" str %s \n argv[1] %s\n",  str, argv[1]);
        base = (argc > 2) ? atoi(argv[2]) : 10;
    
    
        printf("argc %d base %d\n",argc, base);
        errno = 0;    /* To distinguish success/failure after call */
        val = strtol(str, &endptr, base);
            printf("1. strtol() returned %ld\n", val);
        /* Check for various possible errors */
    
        if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
            || (errno != 0 && val == 0)) {
            perror("strtol");
            exit(EXIT_FAILURE);
        }
    
        if (endptr == str) {
            fprintf(stderr, "No digits were found\n");
            exit(EXIT_FAILURE);
        }
    
        /* If we got here, strtol() successfully parsed a number */
    
        printf("strtol() returned %ld\n", val);
    
        if (*endptr != '\0')  {      /* Not necessarily an error... */
            printf("Further characters after number: %s\n", endptr);
    
            exit(EXIT_SUCCESS);
        }
    
    
    }
    main
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    #include "data.h"
    
    int main (int argc, char **argv)
    {
    
    if ( argc > 1)
    printf("argv == %s\n",argv[1]);
    
    
    using_strtoll(argc, argv);
    printf("\n\n");
    
        char *buffer = NULL;
        size_t len;
        int flag = 0;
        long results = 0;
    
    
        printf("input a number\n");
    
        while ( flag != 1 )
        {
            getline(&buffer, &len, stdin);
            results =  int_or_ch(buffer);
    
            if (results == -1)
                    printf("reenter a number\n");
                else
                {
                //    printf("you entered %d\n", results);
                    printf("you entered %li\n", results);
                    flag = 1;
                }
            }
            free(buffer);
    
    return 0;
    }
    Now clean up the code to make it look pretty. then add this function to my other ( real ) program I have
    thanks whiteflags for your inspiration. !


    that seems to work but because I already know I want base 10 I think I'll just assign base = 10; or plug 10 into that strtol function.
    Code:
      base = (len < 10) ? atoi(str1) : 10;
    if len less then 10 just use atoi to get base to equal the value else assign base = 10; which would requite more if statements before the return. what am I thinking , I can work with that.
    Last edited by userxbw; 10-20-2017 at 09:20 AM.

  4. #4
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    948
    What's the purpose of making a copy of the string in int_or_ch? Can't you just use the original string?

  5. #5
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    So you are using the number 123,456,789,012,345 to test. This number requires more bits to store than the standard 32 for long int types. Even if you went unsigned, the highest you can go is 4,294,967,296. If you actually return a 64 bit integer though it will work. Keep in mind that every numerical type has a valid range

    I'm not sure that I understand your logic on the base either. It is going to be base ten because you use isdigit() to check the string.

    Otherwise with these issues fixed it works just fine.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <ctype.h>
    #include <string.h>
    #include <stdint.h>
     
    int64_t int_or_ch(char *data)
    {
        int len = 0, i, base;
        char str1[1+strlen(data)];
        char *ptr, *endptr;
        strcpy(str1, data);
     
        len = strlen(str1);
        ptr = str1;
     
    printf("got length %dand input is %s\n", len, str1);
    //    if (len > 11 )
        //S    return -2;
     
        for ( i = 0; i < len - 1; i++)
        {
            printf("%c\n", ptr[i]);
            // if not a digit return error code -1
            if ( isdigit(ptr[i]) == 0)
                return -1;
         }
         base = 10;
         //base = (len > 11) ? atoi(str1) : 10;
         printf("base %d\n", base);
     
         return strtoll(str1, &endptr, base);
     }
     
     int main(void) {
        printf("%lld\n", int_or_ch("123456789012345"));
        return 0;
     }
    C:\Users\jk\Desktop>sandbox
    got length 15and input is 123456789012345
    1
    2
    3
    4
    5
    6
    7
    8
    9
    0
    1
    2
    3
    4
    base 10
    123456789012345

  6. #6
    Registered User
    Join Date
    May 2015
    Posts
    90
    You are creating a variable then copying data and then using yet another variable, you could just use the parameter as was suggested in the comment above.

    Also I would make sure data is not NULL (just a safety check).

  7. #7
    Banned
    Join Date
    Aug 2017
    Posts
    861
    Quote Originally Posted by christop View Post
    What's the purpose of making a copy of the string in int_or_ch? Can't you just use the original string?
    I do suppose, bad learning habits perhaps? just to have an extra copy around just encase I need it? I doono pick one. thanks for pointing that out.

  8. #8
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Also to be clear, strtoll() already does plenty of validation on the string. The whole point of endptr is to tell you where the conversion stopped so you can decide if the input is good. And if there are other problems, like overflow, it updates errno with ERANGE.

  9. #9
    Banned
    Join Date
    Aug 2017
    Posts
    861
    Quote Originally Posted by whiteflags View Post
    So you are using the number 123,456,789,012,345 to test. This number requires more bits to store than the standard 32 for long int types. Even if you went unsigned, the highest you can go is 4,294,967,296. If you actually return a 64 bit integer though it will work. Keep in mind that every numerical type has a valid range

    I'm not sure that I understand your logic on the base either. It is going to be base ten because you use isdigit() to check the string.

    Otherwise with these issues fixed it works just fine.
    My logic was just looking at the example strol and figuring it out while running it looking at it playing with it, and yeah that return value is what kept be messing up, because if over that int range it was giving me bogas return results, because I forgot to change that so it kept me messing with the code and wondering why I am not getting what I want.

    if you look at me last post #3 as I have modded it. it says that already. and I changed my return type, I think that was my biggest mistake

    the ranges I got to look up again. anyways you do not see the logic in that?

    no matter how long the string is. use isdigit to look through it as char is an array, so as soon as isdigit finds anything in that string that is not a digit 0 - 9, kick it out of the function and give it a -1 error return code, because it is no longer a valid number.

    else return that value that was inputted into it, as something other than a char to be used somewhere else as an int or bigger long long long whatever , just not a char.

    if some silly billy trys to type in a number larger than 1, 234, 567, 890 it will still be able to handle it, regardless what one is going to use that number on on the return. that is up to the programmer to deal with. it can now be said that it is ascii and unicode compatible .

    strtol(3) - Linux manual page
    Last edited by userxbw; 10-20-2017 at 09:48 AM.

  10. #10
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    Sorry about being slow.

    Quote Originally Posted by userxbw
    the ranges I got to look up again. anyways you do not see the logic in that?

    no matter how long the string is. use isdigit to look through it as char is an array, so as soon as isdigit finds anything in that string that is not a digit 0 - 9, kick it out of the function and give it a -1 error return code, because it is no longer a valid number.

    else return that value that was inputted into it, as something other than a char to be used somewhere else as an int or bigger long long long whatever , just not a char.
    No, you are getting off track. I do not need your whole function explained to me. Please read more carefully.

    I said that I didn't understand your logic for the base. If we look at this line again:
    Code:
         //base = (len > 11) ? atoi(str1) : 10;
    This is how you elected to determine the base. This is not good, it doesn't make sense. There is nothing that atoi will do to help you determine the base, so I had to say something. Ten was going to be the base anyway, since you were using isdigit().

    If you want to determine the base, the convention is to prepend numerical strings with codes. 0x is hexadecimal, 0o is octal, 0b is binary, and these are just ones that I've seen. Plus, strtol() attempts to work out the base itself if you pass 0 as the base.

    Hopefully this explains things.
    Last edited by whiteflags; 10-20-2017 at 09:48 AM.

  11. #11
    Banned
    Join Date
    Aug 2017
    Posts
    861
    Quote Originally Posted by whiteflags View Post
    Sorry about being slow.


    No, you are getting off track. I do not need your whole function explained to me. Please read more carefully.

    I said that I didn't understand your logic for the base. If we look at this line again:
    Code:
         //base = (len > 11) ? atoi(str1) : 10;
    This is how you elected to determine the base. This is not good, it doesn't make sense. There is nothing that atoi will do to help you determine the base, so I had to say something. Ten was going to be the base anyway, since you were using isdigit().

    If you want to determine the base, the convention is to prepend numerical strings with codes. 0x is hexadecimal, 0o is octal, 0b is binary, and these are just ones that I've seen. Plus, strtol() attempts to work out the base itself if you pass 0 as the base.

    Hopefully this explains things.
    I was just using the example in the man page in how they where writing it so I just copied it without fully examining it. just assuming ...

    strtol(3) - Linux manual page
    Code:
               str = argv[1];
               base = (argc > 2) ? atoi(argv[2]) : 10;
    but if one actually picks that apart to understand it.
    argc 0 = program name,
    argc 1 = first line after program name
    argc = 2 second line off argc

    so taking
    atoi(argv[2])
    made no real sense to me because it is not converting anything because it is using argv[1] to get the number.
    so it is always going
    return 10 unless some other kind of input format was expected.
    Code:
    $./prog 12345
    // equates to argc 0 - 2 but two is blank.
    Code:
    int main (int argc, char **argv)
    {
    
    if ( argc > 0)
    printf("argv 0 == %s\n",argv[0]);
    printf("argv 1 == %s\n",argv[1]);
    printf("argv 2 == %s\n",argv[2]);
    
    return 0;
    }
    
    // output
    
    userx@slackwhere:~/bin/calculator
    $ ./a.out 123456789012345
    argv 0 == ./a.out
    argv 1 == 123456789012345
    argv 2 == (null)
    so when I just wrote it like this
    Code:
     return strtol(ptr, &endptr, 10);
    I was still getting bad results when I printed it on return to main, because I forgot about my return value it was still an int
    that is why I was still getting a negative number. it was not until I remembered, then changed my return value was
    when I got what I was looking for. but by that time I had already changed a bunch of stuff resulting in what I posted.

    this is just me messing with it
    Code:
       //base = (len > 11) ? atoi(str1) : 10;
    Last edited by userxbw; 10-20-2017 at 10:04 AM.

  12. #12
    Banned
    Join Date
    Aug 2017
    Posts
    861
    Code:
    int64_t int_or_ch(char *data)
    {
        int len = 0, i;
        char *endptr;
    
        len = strlen(data);
    
        for ( i = 0; i < len - 1; i++)
        {// if not a digit return error code -1
            if ( isdigit(data[i]) == 0)
                return -1;
         }
         return strtol(data, &endptr, 10);
    }
    results
    Code:
    userx@slackwhere:~/bin/calculator
    $ ./a.out 
    input a number
    12345678901234567890
    you entered 9223372036854775807

  13. #13
    Citizen of Awesometown the_jackass's Avatar
    Join Date
    Oct 2014
    Location
    Awesometown
    Posts
    269
    Note the return type of 'strtol' and check the number you are inputting. long usually means a 32 bit integer. long long is usually a 64 bit integer.
    "Highbrow philosophical truth: Everybody is an ape in monkeytown" --Oscar Wilde

  14. #14
    Registered User
    Join Date
    Dec 2011
    Location
    Namib desert
    Posts
    94
    Small is beautifull
    Code:
    int64_t int_or_ch(char *data)
    {
        char *ptr;
        ptr = data;
    
        while(*ptr)
            if (isdigit(*ptr++) == 0)
                return(-1);
    
         return strtol(data, NULL, 10);
    }

  15. #15
    Banned
    Join Date
    Aug 2017
    Posts
    861
    Quote Originally Posted by ddutch View Post
    Small is beautifull
    Code:
    int64_t int_or_ch(char *data)
    {
        char *ptr;
        ptr = data;
    
        while(*ptr)
            if (isdigit(*ptr++) == 0)
                return(-1);
    
         return strtol(data, NULL, 10);
    }
    sure is ya got rid of all of the goop'edy glop.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to display single digit int as four digit C++ Programming
    By Sloganathan in forum C++ Programming
    Replies: 1
    Last Post: 03-06-2012, 11:30 AM
  2. Adding a number digit by digit.
    By sdfx in forum C Programming
    Replies: 4
    Last Post: 05-10-2011, 05:54 PM
  3. Read from file - 1-digit and 2-digit numbers
    By Bonaventura in forum C Programming
    Replies: 8
    Last Post: 03-06-2010, 06:33 AM
  4. Adding a Large number digit by digit
    By mejv3 in forum C Programming
    Replies: 23
    Last Post: 09-21-2007, 03:00 PM
  5. Adding a Large number digit by digit
    By mejv3 in forum C Programming
    Replies: 1
    Last Post: 09-14-2007, 03:28 AM

Tags for this Thread