C言語のatoi関数の使い方: 文字列を整数に変換する
目次
atoi関数の使い方
C言語には数字の書かれた文字列をint
型の整数に変換する関数atoi()
があります。
この記事ではatoi
関数の使い方を解説します。
スポンサーリンク
具体的には↓を見ていきます。
- atoi関数の構造
- atoi関数の使い方
- 不正な引数
- atoi()の代わりにstrtol()を使う
atoi関数の構造
atoi
関数はstdlib.h
をインクルードすると使うことが出来ます。
#include <stdlib.h>
atoi
関数は↓のような作りになっています。
int atoi(const char *nptr);
atoi
関数は1つの文字列の引数を取り、int
型の返り値を返します。
atoi
関数はスレッドセーフです。
atoi
関数はエラーを検出しません。
nptr(第1引数)
nptr
はconst 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以降に対応しているコンパイラで使うことが出来ます。
#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
関数は値が範囲外だった場合にerrno
にERANGE
をセットします。
ただしstrtol
関数も引数がNULL
だった場合と、引数が数字じゃなかった場合はエラーになりません。
そのためよりセキュアな関数を使いたい場合はラッパーを作って自作しましょう。
おわりに
C言語でatoi
関数を使う機会はけっこう多いです。
しかしatoi
関数はエラーを検出しないなど、いろいろとクセのある関数です。
場合によってはラッパーを作って対応しましょう。
C言語ってそういう関数多いよね
まぁ時代が時代だからね
やっぱラッパーか外部ライブラリを使うのが正義だな
スポンサーリンク