ユーニックス総合研究所

  • home
  • archives
  • c-atoi

C言語のatoi関数の使い方: 文字列を整数に変換する

  • 作成日: 2020-12-22
  • 更新日: 2024-03-24
  • カテゴリ: C言語

atoi関数の使い方

C言語には数字の書かれた文字列をint型の整数に変換する関数atoi()があります。
この記事ではatoi関数の使い方を解説します。

具体的には↓を見ていきます。

  • atoi関数の構造
  • atoi関数の使い方
  • 不正な引数
  • atoi()の代わりにstrtol()を使う

C言語や他の言語を扱うYoutubeも公開しています。
興味がある方は以下のリンクからご覧ください。

Youtubeの当チャンネル

atoi関数の構造

atoi関数はstdlib.hをインクルードすると使うことが出来ます。

#include <stdlib.h>  

atoi関数は↓のような作りになっています。

int atoi(const char *nptr);  

atoi関数は1つの文字列の引数を取り、int型の返り値を返します。
atoi関数はスレッドセーフです。
atoi関数はエラーを検出しません。

nptr(第1引数)

nptrconst char *型の文字列です。
文字列は↓のようなものが該当します。

"this is string";  
const char *s1 = "this is string";  
char s2[] = "this is string";  

返り値(`int`)

atoi関数の返り値はintです。

atoi関数の使い方

atoi関数の使い方です。
atoi関数の第1引数に数字の書かれた文字列を渡すと、atoi関数は内部でその数字の書かれた文字列をパースし、int型の整数に変換します。
つまり↓のように使うことが出来ます。

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

int  
main(void) {  
    int n = atoi("123");  
    printf("%d\n", n);  
    return 0;  
}  

↑のコードを実行すると結果は↓のようになります。

123  

atoi関数の第1引数はconst char *なので、文字列リテラルの他にもconst char *char *型の変数を渡すことも出来ます。

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

int  
main(void) {  
    const char *s1 = "123";  
    int n1 = atoi(s1);  
    printf("%d\n", n1);  

    char s2[] = "456";  
    int n2 = atoi(s2);  
    printf("%d\n", n2);  
    return 0;  
}  

↑のコードを実行すると↓のような結果になります。

123  
456  

不正な引数

atoi関数はエラーを検出しません。
つまり第1引数が不正だった場合に、atoi関数を使う側はその不正を知るすべがないということです。
不正な引数を渡した場合のatoi関数の挙動を見てみたいと思います。

NULLを渡した場合

atoi関数にNULLを渡した場合、atoi関数はSegmentation faultを起こす可能性があります。

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

int  
main(void) {  
    int n = atoi(NULL);  
    printf("%d\n", n);  
    return 0;  
}  

↑のコードを実行すると↓のような結果になり、実行時エラーになります。

Segmentation fault  

Valgrindなどのメモリチェックツールでチェックしてみると↓のような結果になります。

...  
==6694== Invalid read of size 1  
==6694==    at 0x4E75454: ____strtol_l_internal (strtol_l.c:293)  
==6694==    by 0x4E70E8F: atoi (atoi.c:27)  
==6694==    by 0x400503: main (in /tmp/a.out)  
==6694==  Address 0x0 is not stack'd, malloc'd or (recently) free'd  
...  
Segmentation fault  

↑を見ると「Invalid read of size 1」と表示されているのがわかります。
つまりatoi関数は引数がNULLだった場合、NULLでも気にせずに読み込みに行ってるということになります。
引数がNULLかどうかのチェックはしていないようです。

数字じゃない文字列を渡した場合

atoi関数に数字ではない文字列を渡すとどうなるのでしょうか。

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

int  
main(void) {  
    int n1 = atoi("abc");  
    printf("%d\n", n1);  

    int n2 = atoi("abc123");  
    printf("%d\n", n2);  

    int n3 = atoi("123abc");  
    printf("%d\n", n3);  

    int n4 = atoi("a1b2c");  
    printf("%d\n", n4);  
    return 0;  
}  

↑のコードを実行すると↓のような結果になります。

0  
0  
123  
0  

↑の結果を見ると文字列の先頭が数字でない場合は0を返しているのがわかります。
先頭が数字で始まっていて、途中から数字で無くなった場合は、それまでのパースの結果を返しています(123)。

atoi()の代わりにstrtol()を使う

atoi関数はエラーを検出しないのであまりセキュアな関数ではありません。
エラーを検出したい場合はstrtol関数の使用を検討しましょう。
strtol関数はC99以降に対応しているコンパイラで使うことが出来ます。

関連記事
C言語の文字列を数値変換する【atoi, atof, strtol, strtod, etc】

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

int  
main(void) {  
    errno = 0;  

    long int n = strtol("123456789123456789123456789123456789", NULL, 10);  
    switch (errno) {  
    case ERANGE: perror("strtol(). out of range"); break;  
    }  

    printf("%d\n", n);  
    return 0;  
}  

↑のコードを実行すると↓のような結果になります。

strtol(). out of range: Numerical result out of range  
-1  

↑のようにstrtol関数は値が範囲外だった場合にerrnoERANGEをセットします。
ただしstrtol関数も引数がNULLだった場合と、引数が数字じゃなかった場合はエラーになりません。
そのためよりセキュアな関数を使いたい場合はラッパーを作って自作しましょう。

おわりに

C言語でatoi関数を使う機会はけっこう多いです。
しかしatoi関数はエラーを検出しないなど、いろいろとクセのある関数です。
場合によってはラッパーを作って対応しましょう。

🦝 < C言語ってそういう関数多いよね

🐭 < まぁ時代が時代だからね

🦊 < やっぱラッパーか外部ライブラリを使うのが正義だな