Question

Convert a String to an Integer in C: atoi vs strtol

cstringatoi

Question

How can a numeric string be converted to an int in C? For example:

char s[] = "45";
int num = atoi(s);

Is atoi() the best approach, or is there a safer alternative that can detect invalid input and conversion errors?

Short Answer

You will learn how C converts text such as "45" into integer values, why atoi() is often insufficient, and how to use strtol() to validate input and detect errors such as invalid characters and values outside the int range.

Concept

C stores text in character arrays or string literals, while an int stores a binary numeric value. Converting a string to an integer means reading digit characters such as '4' and '5' and producing the numeric value 45.

atoi() can perform a basic conversion:

int value = atoi("45");

However, atoi() cannot reliably report failure. Both an invalid string and the valid string "0" may result in 0:

atoi("0");       // 0
atoi("hello");   // also 0

For input that may be invalid—such as user input, file contents, command-line arguments, or API data—use strtol() instead. It provides:

  • An end pointer that shows where conversion stopped.
  • errno reporting for values outside the range of long.
  • A selectable numeric base, such as decimal (10) or hexadecimal (16).

Because strtol() returns a long, check that the final result also fits in an int before casting it.

Mental Model

Think of conversion as a cashier reading a price label.

  • atoi() gives the cashier a label and asks for a number back. If the label is unreadable, the cashier still says 0, without explaining why.
  • strtol() gives the cashier a label and a checklist. The cashier can tell you where reading stopped, whether there were unexpected characters, and whether the number was too large.

When input comes from outside your program, you usually need the checklist.

Take Quiz

Syntax and Examples

atoi() is simple but does not provide useful error detection:

#include <stdlib.h>

int number = atoi("45");

For validated conversion, use strtol():

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

int main(void) {
    const char *text = "45";
    char *end;
    long value;

    errno = 0;
    value = strtol(text, &end, 10);

    if (end == text) {
        printf("No number was found.\n");
    } else if (*end != '\0') {
        printf("Unexpected characters after the number: %s\n", end);
    } else if (errno == ERANGE || value < INT_MIN || value > INT_MAX) {
        printf("Number is outside the int range.\n");
    } else {
        int number = (int)value;
        printf("Converted value: %d\n", number);
    }

    return 0;
}

How the important arguments work:

long strtol(const char *text, char **end, int base);
  • text: the string to parse.
  • end: receives the location where parsing stopped.
  • base: 10 for decimal, 16 for hexadecimal, or 0 to infer a prefix such as 0x.

For the string "45", strtol(text, &end, 10) returns 45 and makes end point to the terminating \0 character.

Step by Step Execution

Consider this program fragment:

const char *text = "123abc";
char *end;
long value = strtol(text, &end, 10);

Step by step:

  1. strtol() starts at the first character, '1'.
  2. It reads '1', '2', and '3' because they are valid base-10 digits.
  3. It stops at 'a', because 'a' is not a decimal digit.
  4. value becomes 123.
  5. end points to the substring "abc".
  6. Since *end != '\0', the entire input was not a valid integer.

A complete check looks like this:

if (end == text) {
    /* No digits were converted. */
} else if (*end != '\0') {
    /* Some characters were left over. */
} else {
    /* The complete string was converted. */
}

For "abc", end == text because conversion could not consume even one digit. For "123", *end == '\0' because conversion reached the end of the string.

Real World Use Cases

String-to-integer conversion is needed whenever a number arrives as text:

  • Command-line arguments: Convert ./server 8080 into an integer port number.
  • Configuration files: Read max_connections=100 and validate the value.
  • User input: Convert a menu selection or quantity entered in a terminal program.
  • CSV and log files: Parse fields such as IDs, counts, years, and timestamps.
  • Network protocols: Convert textual headers or message fields into numeric values.

In all of these cases, invalid input is possible. strtol() lets the program reject malformed values rather than silently using an unintended value.

Take Quiz

Real Codebase Usage

In production C code, conversion is commonly placed in a small reusable helper function. This prevents repeated, incomplete checks throughout the program.

A typical pattern is:

  1. Parse into a wider type with strtol().
  2. Check whether no digits were consumed.
  3. Check whether unparsed characters remain.
  4. Check errno for overflow or underflow.
  5. Check the target type's range before casting.
  6. Return a success indicator instead of guessing a default value.

For example:

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

bool parse_int(const char *text, int *result) {
    char *end;
    long value;

    if (text == NULL || result == NULL) {
        return false;
    }

    errno = 0;
    value = strtol(text, &end, 10);

    if (end == text || *end != '\0') {
        return false;
    }

    if (errno == ERANGE || value < INT_MIN || value > INT_MAX) {
        return false;
    }

    *result = (int)value;
    return true;
}

This is an example of a guard clause: invalid cases return early, so the successful path remains short and clear.

Common Mistakes

Using atoi() when validation matters

int value = atoi("invalid");

This produces 0, but 0 might also be a valid input. Use strtol() if the source is not guaranteed to be valid.

Ignoring trailing characters

char *end;
long value = strtol("42cats", &end, 10);
/* value is 42, but the whole string was not a valid integer. */

Check *end == '\0' when the input must contain only an integer.

Forgetting to check whether any digits were read

char *end;
long value = strtol("cats42", &end, 10);

Here, value is 0, but no number was parsed. Detect this with end == text.

Casting before checking the range

long value = strtol(text, &end, 10);
int number = (int)value;  /* Potentially unsafe */

If value cannot fit in an int, the conversion may produce an incorrect result. Check against INT_MIN and INT_MAX first.

Not resetting errno

long value = strtol(text, &end, 10);
if (errno == ERANGE) {
    /* May be reacting to an earlier library call. */
}

Set errno = 0 immediately before calling strtol() when you plan to inspect it.

Using the wrong base

strtol("101", &end, 2);   /* 5, not 101 */

Use base 10 for ordinary decimal input. Use base 0 only when accepting C-style prefixes such as 0xFF.

Comparisons

FunctionResult typeCan detect invalid input?Can detect range errors?Best use
atoi()intNoNo reliable mechanismTrusted, simple legacy code only
strtol()longYes, with endYes, with errnoMost integer parsing in C
strtoll()long longYesYesLarger signed integer values
strtoul()unsigned longYesYesNon-negative unsigned values
sscanf()depends on formatPartlyLess directParsing multiple formatted fields

strtol() is generally preferred over atoi() because it makes validation explicit. sscanf() can parse integers too, but strtol() is often easier to validate precisely when parsing a single number.

Whitespace is accepted at the beginning by both atoi() and strtol():

strtol("   -45", &end, 10);  /* Parses -45 */

If leading whitespace should be rejected, check the first character yourself before conversion.

Take Quiz

Cheat Sheet

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

char *end;
long value;

errno = 0;
value = strtol(text, &end, 10);

if (end == text) {
    /* No digits found. */
} else if (*end != '\0') {
    /* Extra characters remain. */
} else if (errno == ERANGE) {
    /* Value is outside long range. */
} else if (value < INT_MIN || value > INT_MAX) {
    /* Value does not fit in int. */
} else {
    int number = (int)value;
}
  • Use atoi() only when failure does not matter or input is fully trusted.
  • Use strtol(text, &end, 10) for decimal integers.
  • end == text: no number was converted.
  • *end != '\0': trailing invalid characters exist.
  • Set errno = 0 before calling strtol().
  • Check errno == ERANGE for a value outside long range.
  • Check INT_MIN and INT_MAX before converting long to int.

FAQ

Is atoi() safe in C?

atoi() is memory-safe when passed a valid null-terminated string, but it is not suitable for validated input because it cannot report conversion errors or overflow reliably.

What should I use instead of atoi() in C?

Use strtol() for signed integer input. It can show whether conversion failed, whether extra characters remain, and whether the value was out of range.

Why does strtol() return long instead of int?

Returning long gives the function a wider result type on many platforms and provides a standard parsing interface. If you need an int, verify the result fits before casting.

How do I convert a string to an integer with no extra characters?

Call strtol(), then require both end != text and *end == '\0'.

Does strtol() accept negative numbers?

Yes. For example, strtol("-45", &end, 10) returns -45 when it is within range.

Does strtol() accept whitespace?

Yes. It skips leading whitespace. It does not automatically allow arbitrary trailing text; the end pointer lets you detect it.

How do I parse hexadecimal input in C?

Use base 16 for hexadecimal digits, or base 0 to accept prefixes such as 0xFF:

long value = strtol("0xFF", &end, 0);

Can I use strtol() for unsigned integers?

For values intended to be unsigned, use strtoul() and validate its result against the range of the target unsigned type.

Take Quiz

Mini Project

Description

Create a small command-line-style parser for a TCP port number. A port is received as text, but the program must accept only complete decimal integers in the valid port range. This demonstrates parsing, validation, range checks, and clear error messages.

Goal

Write a function that converts a port string into an int only when it contains a valid decimal port number from 1 through 65535.

Requirements

Requirement 1

Take Quiz

Keep learning

Related questions

View more