0

Assume that we have a char array input = "12345678987654321", why cant I use atoi() to convert it into integer 12345678987654321? I have tried this and it returned some numbers that I couldn't understand.

Here is the code:

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

int main() {
    char num[20];
    scanf("%s\n", num);
    printf("%d", atoi(num));
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
welp...
  • 9
  • 6
  • 1
    What is `sizeof int` in your system? What is `INT_MAX`? – Gerhardh Mar 24 '21 at 09:34
  • 1
    Because `atoi` returns an `int` is limited in size and range? Normally to 32 bits which means it will have a range from about minus two billion to plus two billion. – Some programmer dude Mar 24 '21 at 09:34
  • @Gerhardh INT_MAX = 30 – welp... Mar 24 '21 at 09:35
  • @Someprogrammerdude so we need to convert it into double? – welp... Mar 24 '21 at 09:35
  • Also note that [`atoi`](https://en.cppreference.com/w/c/string/byte/atoi) have *no* error checking of any kind. If you want to have error checking and validation use [`strtol`](https://en.cppreference.com/w/c/string/byte/strtol). – Some programmer dude Mar 24 '21 at 09:36
  • 1
    Also the error checking should begin at the input with `scanf("%19s",num);` (and remove the newline). – Weather Vane Mar 24 '21 at 09:37
  • @Someprogrammerdude but then can we use atof? – welp... Mar 24 '21 at 09:42
  • 1
    `float` will not be able to handle numbers that high in a good way (if at all), I'm not sure about `double`. If you want a large integer, use `long long` which, if supported, will have at least 64 bits. – Some programmer dude Mar 24 '21 at 09:50
  • 1
    @welp..., `INT_MAX` definitely is not 30. This is a parameter of the machine's integer representation, exposed automatically to your code in the form of a preprocessor macro. In a conforming C implementation, it will not be less than 32767. In most implementations these days it is in excess of 2 billion. If somehow it really were 30 then your C implementation would be deeply crippled. – John Bollinger Mar 24 '21 at 11:07
  • 1
    The first chapters of any beginner-level C programming book typically address numerical limits of integer types. Start by reading those. See if you can find the magic number 2.14 * 10^9 somewhere, or perhaps the equivalent 2^31 - 1. – Lundin Mar 24 '21 at 11:46
  • strongly suggest using `strtoll()` to do the conversion. Remember to read/understand the MAN page for that function. – user3629249 Mar 25 '21 at 07:43

3 Answers3

2

“12345678987654321” is generally too large for an int, and atoi does not provide error detection.

You can use the strto… functions to convert a numeral in a string to an integer type. Below is an example using strtoimax, for the widest signed integer type a C implementation supports. There are also versions for other types, such as strtoll for long long.

The strto… functions provide error checking, so you can detect when a number is too large and report it to the user or otherwise handle it.

#include <ctype.h>      // For isdigit and isspace.
#include <errno.h>      // For errno.
#include <inttypes.h>   // For stroimax and PRIdMAX.
#include <stdint.h>     // For intmax_t.
#include <stdio.h>      // For printf, fprintf, getchar, and ungetc.
#include <stdlib.h>     // For exit.


int main(void)
{
    // Read string.
    char string[20];
    int n = 0; // Number of characters read so far.
    while (1)
    {
        int c = getchar();

        // When we see the end of the input stream, leave the loop.
        if (c == EOF)
            break;

        /* When we see a white-space character (including new-line), put it
           back into the stream and leave the loop.
        */
        if (isspace(c))
        {
            ungetc(c, stdin);
            break;
        }

        /* If we see character that is not a space or a digit, complain, unless
           it is the first character and is a sign, "+" or "-".
        */
        if (!isdigit(c) && !(n == 0 && (c == '+' || c == '-')))
        {
            fprintf(stderr, "Error, non-digit seen:  \"%c\".\n", c);
            exit(EXIT_FAILURE);
        }

        // Record the digit.
        string[n++] = c;

        if (sizeof string / sizeof *string <= n)
        {
            fprintf(stderr, "Error, too many digits, can handle only %zu.\n",
                sizeof string / sizeof *string - 1);
                /* ("sizeof *string" is one for ordinary "char" arrays, but
                   using it allows changing to wide character types if
                   desired.)
                */
            exit(EXIT_FAILURE);
        }
    };
    // Finish string with a null character.
    string[n] = '\0';

    // Attempt to convert string to an intmax_t.
    char *end;
    errno = 0; // Initialize error indicator.
    intmax_t number = strtoimax(string, &end, 0);

    /* Test whether the string failed to match the form for a numeral, because
       it was empty or was just a sign with no digits.
    */
    if (end == string)
    {
        fprintf(stderr, "Error, numeral has no digits.\n");
        exit(EXIT_FAILURE);
    }

    // Check for error.
    if (errno != 0)
    {
        fprintf(stderr, "Error, number is too large for intmax_t.\n");
        exit(EXIT_FAILURE);
    }

    /* Test whether the whole string was used in the conversion. It should have
       been, considering we ensured each character was a digit, but a check
       like this can be useful in other situations, where we are parsing a
       numeral from a more general string.
    */
    if (*end != 0)
    {
        fprintf(stderr, "Error, unexpected character in numeral, \"%c\".\n",
            *end);
        exit(EXIT_FAILURE);
    }

    // Print the number.
    printf("The number is %" PRIdMAX ".\n", number);
}
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

The reason you get weird output is the number entered is beyond the range of values representable with the int type. The atoi() function does not necessarily perform error checking, it actually has undefined behavior if the number cannot be represented as an int. You should use strtol() instead.

Your program has another potential undefined behavior: scanf("%s\n", num) may write beyond the end of the num array with dire consequences if the user inputs more than 19 characters. You should write scanf("%19s", num) and test the return value for potential conversion errors.

Here is a modified version:

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

int main() {
    char num[20];

    if (scanf("%19s", num) != 1) {
        printf("no input\n");
        return 1;
    }
    int c = getchar();
    if (c != '\n' && c != EOF) {
        printf("too many characters\n");
        ungetc(c, stdin);
    }
    char *end;
    errno = 0;
    long value = strtol(num, &end, 10);
    if (end == num) {
        printf("input is not a number: %s", num);
    } else {
        if (errno != 0) {
            printf("number %s is too large for type long\n", num);
        } else
        if (value < INT_MIN || value > INT_MAX) {
            printf("number %ld is too large for type int\n", value);
        } else {
            printf("value is %d\n", (int)value);
        }
        if (*end != '\0') {
            printf("extra characters after the number: %s", end);
        }
    }
    return 0;
}
chqrlie
  • 131,814
  • 10
  • 121
  • 189
0

you are giving input of "12345678987654321" atoi is in int and the range of int is from -2,147,483,648 - 2,147,483,647 so in order to fix it use atol() l-long,its just because of range or if you are using 32bit machine then you need to use long long int i.e atoll() instead of atol() data size

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
    char num[20];
    scanf("%s",num);
    //printf("\n%s",num);
    printf("\n%ld",atol(num)); //<- atoi(num) to atol(num)
    return 0;
}

atol() check this for more atoi(),atol() and atoll()

MONUDDIN TAMBOLI
  • 152
  • 1
  • 11
  • You are probably right about the range of `int` in the OP's C implementation, but not necessarily. The C language allows implementations to have both narrower and wider ranges for `int`, and both alternatives can be seen in real implementations. – John Bollinger Mar 24 '21 at 11:13
  • @JohnBollinger oh, i understand but not completely can you give me something to read on what you are explaining to me some article or reading material – MONUDDIN TAMBOLI Mar 24 '21 at 11:27
  • 1
    `atol()` has the same problem as `atoi()`: if you pass it `"fish"`, you get a valid integer value out of it. Neither has any way to report an error because every possible return value is a valid result. – Andrew Henle Mar 24 '21 at 11:45
  • 1
    @MONUTAMBOLI, a little Googling on "size of int" or "range of int" would turn up many appropriate results. Among them, this: [Is the size of C int 2 bytes or 4 bytes?](https://stackoverflow.com/questions/11438794/is-the-size-of-c-int-2-bytes-or-4-bytes) For that particular question, be sure to read at least the top three answers. – John Bollinger Mar 24 '21 at 12:45