閉じる

【C言語】文字列から整数へ:atoi(atol,atoll)使い方と注意点

C言語で文字列から整数へ変換する場面はとてもよくあります。

標準ライブラリのatoi(atol, atoll)は簡単に使えて便利ですが、エラー判定やオーバーフローに弱いという重要な落とし穴があります。

この記事では、これらの関数の役割と使い分け、変換ルール、注意点、実用的なサンプルコードを初心者の方でも理解できるように丁寧に解説します。

atoi, atol, atollの基本

文字列を整数に変換する関数の役割

atoiatolatollは、十進数表記の文字列の先頭部分をそれぞれintlonglong longに変換する関数です。

先頭の空白を読み飛ばし、続く任意の符号(+-)連続した数字を解釈して整数値にします。

整数の後ろに文字が続いていても、そこまでで変換を止めます。

重要なのは、atoi系はエラー状態を報告しないことです。

変換できない場合も0を返すため、入力が「0」なのか「不正な文字列」なのかを区別できません。

必要なヘッダと宣言

これらの関数は<stdlib.h>に宣言されています。

使うときは必ずインクルードします。

C言語
/* 必要なヘッダ */
#include <stdlib.h>

/* プロトタイプ(標準ライブラリで定義済み) */
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr); /* C99以降 */

分かりやすくまとめると次のとおりです。

関数戻り値の型対応する範囲マクロ必要ヘッダ
atoiintINT_MININT_MAX<stdlib.h>
atollongLONG_MINLONG_MAX<stdlib.h>
atolllong longLLONG_MINLLONG_MAX<stdlib.h>

範囲の具体的な値は実装依存です。

実際の上限・下限は<limits.h>の各マクロで確認できます。

atoi(atol, atoll)の使い分け

使う型に合わせて選びます。

intに収まる値ならatoi、より大きな範囲が必要ならatolatollを使います。

64ビット整数が必要な場面(例えばIDや大きなカウンタ)ならatollが適切です。

ただし、厳密なエラー判定やオーバーフロー検出が必要な場面ではstrtol/strtollの使用をおすすめします。

詳しくは後述します。

変換のルールと戻り値

空白と+/-の扱い

変換前に、以下の空白類(いずれもisspaceで判定される)が先頭から読み飛ばされます。

  • 半角スペース(’ ’)、タブ(\t)、改行(\n)、復帰(\r)、垂直タブ(\v)、フォームフィード(\f)

その直後にオプションの符号('+'または'-')が1文字だけ解釈されます。

符号の後に続くのは数字である必要があり、例えば「"- 12"」のように符号と数字の間に空白があると変換は行われません(結果は0)。

数字の読み取りと停止条件

数字(’0’〜’9’)が連続している範囲を読み取り、最初に数字以外の文字が現れた地点で変換を停止します。

  • "123abc"」は123まで変換し、'a'で停止します。
  • "abc123"」は先頭が数字ではないため変換されず、戻り値は0です。

変換の基数は常に10です。

先頭の「0」や「0x」には特別な意味はありません。

戻り値の型と範囲

戻り値はそれぞれintlonglong longです。

範囲外の値は表現できません

ただしatoi系では範囲外(オーバーフロー/アンダーフロー)のときの挙動は未定義です。

安全に扱うにはstrtol/strtollを使います。

失敗時(0)とエラー判定の限界

変換できない場合、atoi系は0を返します

このため、「本当に0なのか」「不正入力だったのか」を戻り値だけでは判別できません

またerrnoも設定されません。

  • "0"」→ 0
  • "abc"」→ 0
  • ""」(空文字列)→ 0

オーバーフローの注意

オーバーフローやアンダーフローが発生すると動作は未定義です。

つまり、環境によっては不正な値が返ったり、全く別の結果になったりします。

絶対に避けたい場面ではstrtol/strtollerrnoと終端位置(endptr)を確認してください。

使い方の例

基本の使い方

最もシンプルな例です。

数値のみの文字列をintに変換します。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *s = "12345";   /* 十進数の文字列 */
    int value = atoi(s);       /* 文字列をintに変換 */

    /* 変換結果を表示 */
    printf("s=\"%s\" -> %d\n", s, value);
    return 0;
}
実行結果
s="12345" -> 12345

ポイントの説明

この例では変換に成功し、12345が得られます。

ここまでは簡単ですが、atoiは不正入力やオーバーフローを検出できない点を忘れないでください。

long/long longの例

より大きな値を扱うためにatolatollを使う例です。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *s_long = "1234567890";            /* longに十分収まる例(多くの環境) */
    const char *s_ll   = "1234567890123456789";   /* long long向けの大きな値 */

    long lv = atol(s_long);
    long long llv = atoll(s_ll);

    printf("atol(\"%s\")  = %ld\n", s_long, lv);
    printf("atoll(\"%s\") = %lld\n", s_ll, llv);
    return 0;
}
実行結果
atol("1234567890")  = 1234567890
atoll("1234567890123456789") = 1234567890123456789

ポイントの説明

どの型に収まるかは環境のビット幅に依存します。

確実な上限/下限は<limits.h>LONG_MAX/LLONG_MAXなどで確認してください。

空白や+/-を含む文字列の例

先頭空白と符号を含む例です。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *s1 = "   -42";      /* 先頭空白と負号 */
    const char *s2 = "\t+17\n";     /* タブと正号、末尾に改行 */

    int v1 = atoi(s1);  /* 空白を飛ばし、-42を取得 */
    int v2 = atoi(s2);  /* 空白を飛ばし、+17を取得(改行で停止) */

    printf("atoi(\"%s\") = %d\n", "   -42", v1);
    printf("atoi(\"%s\") = %d\n", "\\t+17\\n", v2);
    return 0;
}
実行結果
atoi("   -42") = -42
atoi("\t+17\n") = 17

補足

符号の後に数字が続かない「"- 12"」のようなケースは変換できません(結果0)。

これはatoiの仕様です。

“123abc”のように途中で文字がある例

数字が途切れた地点で変換が止まることを確認します。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    const char *s1 = "123abc";  /* 123まで有効 */
    const char *s2 = "abc123";  /* 先頭が数字でない */

    int v1 = atoi(s1);          /* 123を取得 */
    int v2 = atoi(s2);          /* 変換不可 -> 0 */

    printf("atoi(\"%s\") = %d\n", s1, v1);
    printf("atoi(\"%s\") = %d\n", s2, v2);
    return 0;
}
実行結果
atoi("123abc") = 123
atoi("abc123") = 0

限界の理解

この挙動は便利なこともありますが、「0」と「失敗」の区別ができないため、入力の妥当性が重要な場面では十分ではありません。

簡単な入力チェックのコツ

本当に整数だけで構成されているかを事前にざっくり確認する小さな関数を書いておくと便利です。

以下は「先頭空白→符号→1文字以上の数字→末尾空白のみ」を許す簡易チェックです。

ただしオーバーフローは検出できません

C言語
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>

/* 文字列sが「空白* 符号? 数字+ 空白*」の形かを判定する */
bool is_int_like(const char *s) {
    if (s == NULL) return false;

    /* 先頭空白をスキップ */
    const unsigned char *p = (const unsigned char *)s;
    while (*p && isspace(*p)) p++;

    /* 符号(+/-)があれば1文字だけ進める */
    if (*p == '+' || *p == '-') p++;

    /* 少なくとも1文字の数字が必要 */
    if (!isdigit(*p)) return false;
    while (*p && isdigit(*p)) p++;

    /* 残りは空白のみならOK */
    while (*p) {
        if (!isspace(*p)) return false;
        p++;
    }
    return true;
}

int main(void) {
    const char *tests[] = { "42", "   -7", "+0", "123abc", "- 12", "", NULL };
    for (int i = 0; tests[i] != NULL; i++) {
        printf("\"%s\" -> %s", tests[i], is_int_like(tests[i]) ? "OK" : "NG");
        if (is_int_like(tests[i])) {
            /* チェックを通ったらatoiを使う(オーバーフローは依然として未検出) */
            printf(", atoi=%d", atoi(tests[i]));
        }
        putchar('\n');
    }
    return 0;
}
実行結果
"42" -> OK, atoi=42
"   -7" -> OK, atoi=-7
"+0" -> OK, atoi=0
"123abc" -> NG
"- 12" -> NG
"" -> NG

実務での注意

この方法はあくまで表面的な入力構文の確認です。

桁あふれの検出はできません

厳密に扱う場合は次章のstrtol/strtollを使います。

よくある疑問と注意点

数値以外を含む文字列はどうなる?

先頭から見て数字の連続部分までが変換対象です。

途中の文字で停止し、それ以降は無視されます。

先頭が数字でなければ0が返ります。

空文字列やNULLを渡すと?

  • 空文字列""変換できず0になります。
  • NULLポインタを渡すのは未定義動作です。多くの環境でクラッシュの原因になります。必ずNULLチェックを行ってください。

先頭が0や0xの扱い

atoi系は常に10進数として解釈します。

先頭の0は単なる桁で、"0123"123です。

"0x10"のような16進数表記は認識しません。

"0x10"」は0(最初の'0'のみ変換)になります。

動作を確認する小さな例を示します。

C言語
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    printf("atoi(\"0123\")  = %d\n", atoi("0123"));   /* 123 */
    printf("atoi(\"0x10\")  = %d\n", atoi("0x10"));   /* 0   -> '0'で停止 */
    printf("atoi(\"00042\") = %d\n", atoi("00042"));  /* 42  */
    return 0;
}
実行結果
atoi("0123")  = 123
atoi("0x10")  = 0
atoi("00042") = 42

負の数の変換

負号'-'は1文字のみ認識され、"-42"-42になります。

符号の直後に数字が必要で、"- 42"のように空白が挟まると変換は行われません(結果0)。

"-0"0です。

エラーを厳密に扱いたい場合

エラー検出やオーバーフロー判定が必要ならatoi系は使わずstrtol/strtollを使います。

endptrでどこまで読めたかを確認し、errnoで範囲外(ERANGE)を検出します。

以下はint相当の範囲に収まるか確認する例です。

C言語
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>

/* 文字列sを厳密にintへ変換し、成功時に*outへ設定して1を返す。失敗時は0を返す。 */
int strict_to_int(const char *s, int *out) {
    if (s == NULL || out == NULL) return 0;

    errno = 0;
    char *end = NULL;
    long v = strtol(s, &end, 10);  /* 10進として変換 */

    /* 1) 変換不能(先頭で詰まる)を排除 */
    if (s == end) return 0;

    /* 2) 末尾にゴミがないか(必要なら末尾空白は許可してもよい) */
    while (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r' || *end == '\f' || *end == '\v') end++;
    if (*end != '
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
/* 文字列sを厳密にintへ変換し、成功時に*outへ設定して1を返す。失敗時は0を返す。 */
int strict_to_int(const char *s, int *out) {
if (s == NULL || out == NULL) return 0;
errno = 0;
char *end = NULL;
long v = strtol(s, &end, 10);  /* 10進として変換 */
/* 1) 変換不能(先頭で詰まる)を排除 */
if (s == end) return 0;
/* 2) 末尾にゴミがないか(必要なら末尾空白は許可してもよい) */
while (*end == ' ' || *end == '\t' || *end == '\n' || *end == '\r' || *end == '\f' || *end == '\v') end++;
if (*end != '\0') return 0;
/* 3) オーバーフロー/アンダーフロー検出 */
if (errno == ERANGE) return 0;
/* 4) intに収まるか確認 */
if (v < INT_MIN || v > INT_MAX) return 0;
*out = (int)v;
return 1;
}
int main(void) {
const char *tests[] = {
"2147483647",      /* INT_MAX(多くの環境) */
"2147483648",      /* INT_MAX+1 -> 失敗 */
"  -123  ",        /* OK(空白あり) */
"123abc",          /* 末尾にゴミ -> 失敗 */
"",                /* 失敗 */
NULL
};
for (int i = 0; tests[i] != NULL; i++) {
int out = 0;
int ok = strict_to_int(tests[i], &out);
printf("\"%s\" -> %s", tests[i], ok ? "OK" : "NG");
if (ok) printf(", value=%d", out);
putchar('\n');
}
return 0;
}
') return 0; /* 3) オーバーフロー/アンダーフロー検出 */ if (errno == ERANGE) return 0; /* 4) intに収まるか確認 */ if (v < INT_MIN || v > INT_MAX) return 0; *out = (int)v; return 1; } int main(void) { const char *tests[] = { "2147483647", /* INT_MAX(多くの環境) */ "2147483648", /* INT_MAX+1 -> 失敗 */ " -123 ", /* OK(空白あり) */ "123abc", /* 末尾にゴミ -> 失敗 */ "", /* 失敗 */ NULL }; for (int i = 0; tests[i] != NULL; i++) { int out = 0; int ok = strict_to_int(tests[i], &out); printf("\"%s\" -> %s", tests[i], ok ? "OK" : "NG"); if (ok) printf(", value=%d", out); putchar('\n'); } return 0; }
実行結果
"2147483647" -> OK, value=2147483647
"2147483648" -> NG
"  -123  " -> OK, value=-123
"123abc" -> NG
"" -> NG

このアプローチなら「0」と「失敗」を正確に区別でき、範囲外も検出できます。

まとめ

結論として、atoi(atol, atoll)は「ざっくり変換して結果だけ使う」用途には手軽ですが、エラー判定とオーバーフローに関しては未定義動作を含むため危険です。

先頭空白や符号、数字の読み取りと停止条件などの基本仕様を理解しつつ、入力の妥当性や安全性が重要な場面ではstrtol/strtollを使うのがベストプラクティスです。

型の選択はint/long/long longの必要な範囲で行い、実際の上限・下限は<limits.h>で確認してください。

これらのポイントを押さえれば、文字列から整数への変換を安全かつ確実に行えます。

C言語 標準ライブラリの活用
この記事を書いた人
エーテリア編集部
エーテリア編集部

プログラミングの基礎をしっかり学びたい方向けに、C言語の基本文法から解説しています。ポインタやメモリ管理も少しずつ理解できるよう工夫しています。

クラウドSSLサイトシールは安心の証です。

URLをコピーしました!