C++のatoi関数とは
C++のatoi関数は、C形式の文字列をint型の整数へ変換するための関数です。
たとえば、文字列として保存されている"123"を整数の123へ変換したい場合に使用できます。
atoiはC言語由来の関数ですが、C++でも利用できます。
ただし、変換エラーを細かく判定できないなどの制約があるため、新しいC++コードではstd::stoiやstd::from_charsが適している場合もあります。
atoi関数の基本構文
C++では<cstdlib>ヘッダーをインクルードして使用します。
#include <cstdlib>
int atoi(const char* str);
C++では通常、std::を付けて次のように記述します。
std::atoi(str);
基本的な使用例は以下のとおりです。
#include <iostream>
#include <cstdlib>
int main()
{
const char* str = "123";
int num = std::atoi(str);
std::cout << num << std::endl;
return 0;
}
実行結果は以下です。
123
文字列"123"が整数値123へ変換されています。
atoi関数で文字列を整数に変換する方法
正の整数を変換する
通常の正の整数はそのまま変換できます。
#include <iostream>
#include <cstdlib>
int main()
{
const char* str = "500";
int num = std::atoi(str);
std::cout << num << std::endl;
return 0;
}
実行結果は以下です。
500
負の整数を変換する
atoiは先頭のマイナス記号にも対応しています。
const char* str = "-250";
int num = std::atoi(str);
この場合、numには-250が格納されます。
プラス記号付きの整数も変換できる
先頭に+が付いていても変換できます。
const char* str = "+100";
int num = std::atoi(str);
結果は100です。
atoi関数は先頭の空白文字を読み飛ばす
数字の前に空白があっても変換できる
atoiは、数値の前にある空白文字を読み飛ばしてから整数を解析します。
#include <iostream>
#include <cstdlib>
int main()
{
const char* str = " 123";
int num = std::atoi(str);
std::cout << num << std::endl;
return 0;
}
実行結果は以下です。
123
半角スペースだけでなく、タブや改行など、空白として扱われる文字が先頭にあっても読み飛ばされます。
ただし、std::from_charsではこのような先頭の空白文字を自動的に読み飛ばさないため、置き換える際には注意が必要です。
数字の後ろに文字がある場合の動作
数字として読める位置まで変換される
atoiは、文字列の先頭から整数として解釈できる部分を読み取ります。
たとえば以下のコードです。
const char* str = "123abc";
int num = std::atoi(str);
結果は次のようになります。
123
123までは整数として解析できるため、その部分だけが変換されます。
aに到達した時点で整数としての解析が終了します。
途中に文字がある場合もそこで終了する
次の例でも同様です。
const char* str = "98xyz76";
int num = std::atoi(str);
結果は98です。
つまり、atoiは文字列全体が正しい整数表現になっているかどうかを確認する関数ではありません。
入力値の検証が必要な場合には注意が必要です。
数字から始まらない文字列を渡した場合
変換できない場合は0が返される
整数として変換できる部分が存在しない場合、atoiは0を返します。
#include <iostream>
#include <cstdlib>
int main()
{
const char* str = "abc";
int num = std::atoi(str);
std::cout << num << std::endl;
return 0;
}
実行結果は以下です。
0
ただし、この仕様には重要な注意点があります。
std::atoi("0");
も0を返します。
一方で、
std::atoi("abc");
も0を返します。
そのため、戻り値だけでは「正常に0へ変換された」のか、「変換に失敗した」のかを区別できません。
これはatoiの大きな弱点です。
std::stringをatoiで変換する方法
c_str関数を使用する
atoiが受け取る引数はconst char*です。
そのため、std::stringをそのまま渡すことはできません。
std::string str = "123";
// std::atoi(str); // そのままでは使用できない
std::stringを使用する場合は、c_str()でC形式の文字列を取得します。
#include <iostream>
#include <string>
#include <cstdlib>
int main()
{
std::string str = "123";
int num = std::atoi(str.c_str());
std::cout << num << std::endl;
return 0;
}
実行結果は以下です。
123
ただし、std::stringから整数へ変換するだけであれば、C++11以降ではstd::stoiを利用する方法もあります。
atoi関数に小数を渡した場合
小数点の直前までが整数として解析される
atoiは整数変換用の関数です。
そのため、浮動小数点数として文字列全体を変換することはできません。
たとえば以下のコードです。
const char* str = "12.34";
int num = std::atoi(str);
結果は次のようになります。
12
この動作は、12.34を浮動小数点数として読み込んでから小数部分を切り捨てているわけではありません。
12までは整数として解釈できますが、.に到達した時点で解析が終了しているためです。
小数を変換したい場合は、用途に応じてstd::stodやstd::strtodなどを使用します。
atoi関数は10進数として変換する
0から始まっても8進数にはならない
atoiは整数を10進数として解析します。
そのため、次のコードでは、
std::atoi("0123");
結果は123です。
先頭に0が付いているからといって、8進数として扱われるわけではありません。
0xを付けても16進数にはならない
次のコードにも注意が必要です。
std::atoi("0x2A");
atoiは16進数の42として解析しません。
先頭の0までは10進数字として読めますが、その次のxで解析が終了するため、結果は0になります。
16進数や8進数などの基数を指定した変換を行いたい場合は、std::strtolなどを使用すると便利です。
atoi関数でオーバーフローが発生する場合
intの範囲を超える値には注意する
atoiの戻り値はint型です。
そのため、変換結果がint型で表現可能な範囲を超える場合には注意が必要です。
たとえば以下のようなコードです。
const char* str = "999999999999999999999999";
int num = std::atoi(str);
変換結果をint型で表現できない場合、C++標準上では動作が未定義になります。
つまり、必ず最大値になる、最小値になる、エラーになる、といった保証はありません。
外部入力など、範囲外の値が入力される可能性がある場合は、atoiではなくstd::strtolやstd::from_charsなどを検討したほうが安全です。
atoi関数とstoi関数の違い
stoiは変換エラーを例外で判定できる
C++11以降では、std::stringを整数へ変換するためにstd::stoiが用意されています。
#include <iostream>
#include <string>
int main()
{
std::string str = "123";
int num = std::stoi(str);
std::cout << num << std::endl;
return 0;
}
結果は以下です。
123
std::stoiでは、整数に変換できない場合にstd::invalid_argumentが送出されます。
また、変換結果が範囲外の場合にはstd::out_of_rangeが送出されます。
#include <iostream>
#include <string>
int main()
{
try
{
std::string str = "abc";
int num = std::stoi(str);
std::cout << num << std::endl;
}
catch (const std::invalid_argument&)
{
std::cout << "整数に変換できません" << std::endl;
}
catch (const std::out_of_range&)
{
std::cout << "intの範囲を超えています" << std::endl;
}
}
atoiよりも変換エラーを明確に扱いやすい点が特徴です。
atoiとstoiの違いを比較
主な違いをまとめると以下のようになります。
| 項目 | std::atoi | std::stoi |
|---|---|---|
| 主な入力 | const char* | std::string |
| 戻り値 | int | int |
| 変換不可 | 0 | std::invalid_argument |
| 範囲外 | 未定義動作 | std::out_of_range |
| C++での利用 | C由来 | C++11以降 |
| エラー判定 | 難しい | しやすい |
入力値が必ず正しいと分かっている簡単な処理ではatoiでも十分な場合があります。
一方、変換失敗や範囲外の値を判定する必要がある場合には、std::stoiのほうが扱いやすいでしょう。
stoiでも文字列全体を確認する必要がある
123abcも123として変換される
std::stoiを使えば、文字列全体が自動的に整数として正しいか確認されるわけではありません。
たとえば、
std::stoi("123abc");
は123として変換できます。
文字列全体が整数だったか確認したい場合は、pos引数を利用します。
#include <iostream>
#include <string>
int main()
{
std::string str = "123abc";
std::size_t pos = 0;
int num = std::stoi(str, &pos);
if (pos == str.size())
{
std::cout << "文字列全体が整数です" << std::endl;
}
else
{
std::cout << "整数以外の文字が含まれています" << std::endl;
}
return 0;
}
入力値を厳密に検証する場合には、このような確認が必要です。
atoi関数とstrtol関数の違い
strtolなら変換終了位置を取得できる
C形式の文字列を扱いながら、atoiより詳細に変換結果を確認したい場合にはstd::strtolが利用できます。
#include <iostream>
#include <cstdlib>
int main()
{
const char* str = "123abc";
char* end = nullptr;
long num = std::strtol(str, &end, 10);
std::cout << "数値: " << num << std::endl;
std::cout << "残り: " << end << std::endl;
return 0;
}
実行結果は以下のようになります。
数値: 123
残り: abc
strtolでは、どこまで文字列を変換したかを確認できます。
また、errnoと組み合わせることで範囲エラーも判定できます。
基数も指定できるため、10進数以外の文字列を変換したい場合にも利用できます。
C++17以降ではfrom_charsも利用できる
例外を使わずに変換結果を判定できる
C++17では<charconv>にstd::from_charsが追加されました。
整数の文字列変換を効率よく行いたい場合に利用できます。
#include <charconv>
#include <iostream>
#include <string>
int main()
{
std::string str = "123";
int num = 0;
auto result = std::from_chars(
str.data(),
str.data() + str.size(),
num
);
if (result.ec == std::errc{})
{
std::cout << num << std::endl;
}
return 0;
}
std::from_charsは例外を送出せず、エラーコードによって変換結果を確認できます。
変換できない場合はstd::errc::invalid_argument、範囲外の場合はstd::errc::result_out_of_rangeとして判定できます。
atoiとfrom_charsでは解析ルールが異なる
std::from_charsはatoiと完全に同じ動作をするわけではありません。
整数版のstd::from_charsでは、先頭の空白文字を自動的に読み飛ばしません。
また、先頭の+も整数版では認識されません。
たとえば、
std::atoi("+123");
は123になりますが、同じ文字列をそのままstd::from_charsへ渡しても同じようには変換されません。
そのため、atoiからstd::from_charsへ置き換える場合は、入力文字列の形式にも注意する必要があります。
atoi関数を使用するときの注意点
nullptrを渡さない
atoiは、有効なヌル終端文字列を指すポインタを受け取ることを前提としています。
次のようなコードは使用してはいけません。
const char* str = nullptr;
int num = std::atoi(str);
ポインタがnullptrになる可能性がある場合は、事前に確認します。
if (str != nullptr)
{
int num = std::atoi(str);
}
変換失敗と数値の0を区別できない
次の2つはどちらも0になります。
std::atoi("0");
std::atoi("abc");
そのため、入力値が正常に変換できたかを厳密に確認する必要がある処理には向いていません。
文字列全体の妥当性を確認できない
次の文字列も123として変換されます。
std::atoi("123abc");
ユーザー入力や設定ファイルなど、文字列全体が正しい整数である必要がある場合には、別途チェックする必要があります。
範囲外の値を安全に検出できない
atoiでは、int型の範囲を超える値を安全にエラーとして検出できません。
信頼できない入力を扱う場合には、std::stoi、std::strtol、std::from_charsなどの利用を検討するとよいでしょう。
atoi関数はどのような場面で使うべきか
入力が正しいと保証されている簡単な処理
入力される文字列が確実に整数であり、範囲内であることが保証されている場合には、atoiは簡潔に利用できます。
const char* value = "100";
int num = std::atoi(value);
特に、C言語由来のAPIや既存コードでconst char*を扱っている場合には利用しやすい関数です。
ユーザー入力では別の方法を検討する
ユーザー入力では、次のような文字列が渡される可能性があります。
abc
123abc
999999999999999999
このような入力を適切に処理する必要がある場合、atoiだけでは十分なエラーチェックができません。
用途に応じてstd::stoi、std::strtol、std::from_charsなどを使用するほうが適しています。
C++のatoi関数の使い方まとめ
std::atoiは、C形式の文字列をint型の整数へ変換するためのシンプルな関数です。
基本的な使い方は以下です。
#include <cstdlib>
const char* str = "123";
int num = std::atoi(str);
std::stringを使用する場合は、c_str()を利用できます。
std::string str = "123";
int num = std::atoi(str.c_str());
atoiには、先頭の空白を読み飛ばせる、符号付き整数を簡単に変換できるといった特徴があります。
一方で、変換失敗と0を区別できない、文字列全体の妥当性を確認できない、範囲外の値では未定義動作になるといった注意点もあります。
入力値が確実に正しい簡単な処理や、既存のC形式のコードではatoiを利用できます。
ただし、新しくC++のプログラムを作成する場合には、エラー処理の必要性やパフォーマンスなどを考慮し、std::stoiやstd::from_charsなども使い分けるとよいでしょう。
以上、C++のatoi関数の使い方についてでした。
最後までお読みいただき、ありがとうございました。
