How to convert a string to integer in C?

后端 未结 12 1544
清酒与你
清酒与你 2020-11-22 01:40

I am trying to find out if there is an alternative way of converting string to integer in C.

I regularly pattern the following in my code.

char s[] =         


        
相关标签:
12条回答
  • 2020-11-22 01:46

    Robust C89 strtol-based solution

    With:

    • no undefined behavior (as could be had with the atoi family)
    • a stricter definition of integer than strtol (e.g. no leading whitespace nor trailing trash chars)
    • classification of the error case (e.g. to give useful error messages to users)
    • a "testsuite"
    #include <assert.h>
    #include <ctype.h>
    #include <errno.h>
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    typedef enum {
        STR2INT_SUCCESS,
        STR2INT_OVERFLOW,
        STR2INT_UNDERFLOW,
        STR2INT_INCONVERTIBLE
    } str2int_errno;
    
    /* Convert string s to int out.
     *
     * @param[out] out The converted int. Cannot be NULL.
     *
     * @param[in] s Input string to be converted.
     *
     *     The format is the same as strtol,
     *     except that the following are inconvertible:
     *
     *     - empty string
     *     - leading whitespace
     *     - any trailing characters that are not part of the number
     *
     *     Cannot be NULL.
     *
     * @param[in] base Base to interpret string in. Same range as strtol (2 to 36).
     *
     * @return Indicates if the operation succeeded, or why it failed.
     */
    str2int_errno str2int(int *out, char *s, int base) {
        char *end;
        if (s[0] == '\0' || isspace(s[0]))
            return STR2INT_INCONVERTIBLE;
        errno = 0;
        long l = strtol(s, &end, base);
        /* Both checks are needed because INT_MAX == LONG_MAX is possible. */
        if (l > INT_MAX || (errno == ERANGE && l == LONG_MAX))
            return STR2INT_OVERFLOW;
        if (l < INT_MIN || (errno == ERANGE && l == LONG_MIN))
            return STR2INT_UNDERFLOW;
        if (*end != '\0')
            return STR2INT_INCONVERTIBLE;
        *out = l;
        return STR2INT_SUCCESS;
    }
    
    int main(void) {
        int i;
        /* Lazy to calculate this size properly. */
        char s[256];
    
        /* Simple case. */
        assert(str2int(&i, "11", 10) == STR2INT_SUCCESS);
        assert(i == 11);
    
        /* Negative number . */
        assert(str2int(&i, "-11", 10) == STR2INT_SUCCESS);
        assert(i == -11);
    
        /* Different base. */
        assert(str2int(&i, "11", 16) == STR2INT_SUCCESS);
        assert(i == 17);
    
        /* 0 */
        assert(str2int(&i, "0", 10) == STR2INT_SUCCESS);
        assert(i == 0);
    
        /* INT_MAX. */
        sprintf(s, "%d", INT_MAX);
        assert(str2int(&i, s, 10) == STR2INT_SUCCESS);
        assert(i == INT_MAX);
    
        /* INT_MIN. */
        sprintf(s, "%d", INT_MIN);
        assert(str2int(&i, s, 10) == STR2INT_SUCCESS);
        assert(i == INT_MIN);
    
        /* Leading and trailing space. */
        assert(str2int(&i, " 1", 10) == STR2INT_INCONVERTIBLE);
        assert(str2int(&i, "1 ", 10) == STR2INT_INCONVERTIBLE);
    
        /* Trash characters. */
        assert(str2int(&i, "a10", 10) == STR2INT_INCONVERTIBLE);
        assert(str2int(&i, "10a", 10) == STR2INT_INCONVERTIBLE);
    
        /* int overflow.
         *
         * `if` needed to avoid undefined behaviour
         * on `INT_MAX + 1` if INT_MAX == LONG_MAX.
         */
        if (INT_MAX < LONG_MAX) {
            sprintf(s, "%ld", (long int)INT_MAX + 1L);
            assert(str2int(&i, s, 10) == STR2INT_OVERFLOW);
        }
    
        /* int underflow */
        if (LONG_MIN < INT_MIN) {
            sprintf(s, "%ld", (long int)INT_MIN - 1L);
            assert(str2int(&i, s, 10) == STR2INT_UNDERFLOW);
        }
    
        /* long overflow */
        sprintf(s, "%ld0", LONG_MAX);
        assert(str2int(&i, s, 10) == STR2INT_OVERFLOW);
    
        /* long underflow */
        sprintf(s, "%ld0", LONG_MIN);
        assert(str2int(&i, s, 10) == STR2INT_UNDERFLOW);
    
        return EXIT_SUCCESS;
    }
    

    GitHub upstream.

    Based on: https://stackoverflow.com/a/6154614/895245

    0 讨论(0)
  • 2020-11-22 01:47

    You can always roll your own!

    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    
    int my_atoi(const char* snum)
    {
        int idx, strIdx = 0, accum = 0, numIsNeg = 0;
        const unsigned int NUMLEN = (int)strlen(snum);
    
        /* Check if negative number and flag it. */
        if(snum[0] == 0x2d)
            numIsNeg = 1;
    
        for(idx = NUMLEN - 1; idx >= 0; idx--)
        {
            /* Only process numbers from 0 through 9. */
            if(snum[strIdx] >= 0x30 && snum[strIdx] <= 0x39)
                accum += (snum[strIdx] - 0x30) * pow(10, idx);
    
            strIdx++;
        }
    
        /* Check flag to see if originally passed -ve number and convert result if so. */
        if(!numIsNeg)
            return accum;
        else
            return accum * -1;
    }
    
    int main()
    {
        /* Tests... */
        printf("Returned number is: %d\n", my_atoi("34574"));
        printf("Returned number is: %d\n", my_atoi("-23"));
    
        return 0;
    }
    

    This will do what you want without clutter.

    0 讨论(0)
  • 2020-11-22 01:47

    Ok, I had the same problem.I came up with this solution.It worked for me the best.I did try atoi() but didn't work well for me.So here is my solution:

    void splitInput(int arr[], int sizeArr, char num[])
    {
        for(int i = 0; i < sizeArr; i++)
            // We are subtracting 48 because the numbers in ASCII starts at 48.
            arr[i] = (int)num[i] - 48;
    }
    
    0 讨论(0)
  • 2020-11-22 01:48

    Just wanted to share a solution for unsigned long aswell.

    unsigned long ToUInt(char* str)
    {
        unsigned long mult = 1;
        unsigned long re = 0;
        int len = strlen(str);
        for(int i = len -1 ; i >= 0 ; i--)
        {
            re = re + ((int)str[i] -48)*mult;
            mult = mult*10;
        }
        return re;
    }
    
    0 讨论(0)
  • 2020-11-22 01:57

    In C++, you can use a such function:

    template <typename T>
    T to(const std::string & s)
    {
        std::istringstream stm(s);
        T result;
        stm >> result;
    
        if(stm.tellg() != s.size())
            throw error;
    
        return result;
    }
    

    This can help you to convert any string to any type such as float, int, double...

    0 讨论(0)
  • 2020-11-22 01:58

    This function will help you

    int strtoint_n(char* str, int n)
    {
        int sign = 1;
        int place = 1;
        int ret = 0;
    
        int i;
        for (i = n-1; i >= 0; i--, place *= 10)
        {
            int c = str[i];
            switch (c)
            {
                case '-':
                    if (i == 0) sign = -1;
                    else return -1;
                    break;
                default:
                    if (c >= '0' && c <= '9')   ret += (c - '0') * place;
                    else return -1;
            }
        }
    
        return sign * ret;
    }
    
    int strtoint(char* str)
    {
        char* temp = str;
        int n = 0;
        while (*temp != '\0')
        {
            n++;
            temp++;
        }
        return strtoint_n(str, n);
    }
    

    Ref: http://amscata.blogspot.com/2013/09/strnumstr-version-2.html

    0 讨论(0)
提交回复
热议问题