C言語のatoi関数の使い方: 文字列を整数に変換する
- 作成日: 2020-12-22
- 更新日: 2024-03-24
- カテゴリ: C言語
atoi関数の使い方
C言語には数字の書かれた文字列をint
型の整数に変換する関数atoi()
があります。
この記事ではatoi
関数の使い方を解説します。
具体的には↓を見ていきます。
- atoi関数の構造
- atoi関数の使い方
- 不正な引数
- atoi()の代わりにstrtol()を使う
C言語や他の言語を扱うYoutubeも公開しています。
興味がある方は以下のリンクからご覧ください。
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以降に対応しているコンパイラで使うことが出来ます。
関連記事
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
関数は値が範囲外だった場合にerrno
にERANGE
をセットします。
ただしstrtol
関数も引数がNULL
だった場合と、引数が数字じゃなかった場合はエラーになりません。
そのためよりセキュアな関数を使いたい場合はラッパーを作って自作しましょう。
おわりに
C言語でatoi
関数を使う機会はけっこう多いです。
しかしatoi
関数はエラーを検出しないなど、いろいろとクセのある関数です。
場合によってはラッパーを作って対応しましょう。
🦝 < C言語ってそういう関数多いよね
🐭 < まぁ時代が時代だからね
🦊 < やっぱラッパーか外部ライブラリを使うのが正義だな