Convert a string to an int with negative numbers

Viewed 8136

I need to write a function in C that converts a string (data pointed to by a char *) to an int. I've already done this successfully with this code:

int charTOint(char * c) {
    char p = *c;
    int ergebnis = 0;

    while (p) {
        ergebnis = ergebnis * 10 + (p - '0');
        c++;
        p = *c;
    }

    return ergebnis;
}

My problem now is, that I need it to also work with negative numbers / char arrays starting with a '-'.

I know that I have to check, whether the first char is a '-', but I'm stuck after that.

I know the '-' is the 45th character of the ASCII table, but I somehow can't think of a way to make it work.

2 Answers

I've already done this successfully (with positive) with this code:

Good. An important insight is to build on success.

As int charTOint(char * c) { works well with positive values, perhaps re-write it using unsigned. We get more range as UINT_MAX is typically greater than INT_MAX.

unsigned charTOunsigned(const char * c) {
    char p = *c;
    unsigned ergebnis = 0;
    while (p) {
        ergebnis = ergebnis * 10 + (p - '0');
        c++;
        p = *c;
    }
    return ergebnis;
}

I need it to also work with negative numbers / char arrays starting with a '-'.

Now armed with charTOunsigned(), use that variation of good existing code to re-make a int charTOint() that meets the additional goal. With the usual extra positive range of charTOunsigned(), int charTOint() will readily handle a string that converts to INT_MIN.

int charTOint(const char * c) {
  return (*c == '-') ? -charTOunsigned(c+ 1) : charTOunsigned(c);
}

Certainly one could code a stand-alone charTOint(), yet I wanted to emphasize code re-use. That makes for a productive coder.

Another variable could be added to recognize the sign. Then multiply by the sign variable.
A check should be added to confirm that only digits are processed. If the input was 123abc, this will stop after 123

int charTOint(char * c) {
    char p = *c;
    int ergebnis = 0;
    int sign = 1;

    if ( '-' == *c || '+' == *c) {
        if ( '-' == *c) {
            sign = -1;
        }
        c++;
    }
    while (*c) {
        p = *c - '0';
        if ( 0 <= p && 9 >= p) {// digit 0 to 9
            ergebnis = ergebnis * 10 + p;
            c++;
        }
        else {
            break;//not a digit
        }
    }

    return ergebnis * sign;
}

EDIT 3:

#include <stdio.h>
#include <string.h>
#include <limits.h>

int charTOint(char *c, int *number) {
    char p = *c;
    int sign = 1;
    int divmax = INT_MAX / 10;
    int divmin = INT_MIN / 10;

    *number = 0;
    while ( ' ' == *c || '\t' == *c) {
        c++;//skip leading spaces tabs
    }
    if ( '-' == *c || '+' == *c) {
        if ( '-' == *c) {
            sign = -1;
        }
        c++;
    }
    while (*c) {
        p = *c - '0';
        if ( 0 <= p && 9 >= p) {// digit 0 to 9
            if ( *number <= divmax && *number * 10 <= INT_MAX - p) {
                *number = *number * 10 + p;
                c++;
            }
            else {
                if ( sign < 0 && *number * sign >= divmin && *number * sign * 10 >= INT_MIN + p) {
                    *number = *number * sign * 10 - p;
                    return 1;
                }
                fprintf ( stderr, "\n\t\tOVERFLOW\n\n");
                *number = 0;
                return 0;
            }
        }
        else {
            *number = 0;
            return 0;//not a digit
        }
    }

    *number = *number * sign;
    return 1;
}

int main ( void) {
    char text[100] = "";
    int value = 0;

    do {
        printf ( "enter an integer or enter done\n");
        if ( fgets ( text, sizeof text, stdin)) {
            text[strcspn ( text, "\n")] = 0;
            if ( charTOint ( text, &value)) {
                printf ( "value = %d\n", value);
            }
            else {
                printf ( "input [%s]\n", text);
            }
        }
        else {
            fprintf ( stderr, "fgets EOF\n");
            return 0;
        }
    } while ( strcmp ( text, "done"));
    return 0;
}
Related