質問
文字列に大きな数字を保存していて、1桁の数字を抽出しようとしています。しかし、これらの呼び出しの違いは何ですか?
#include <iostream>
#include <string>
int main(){
std::string bigNumber = "93485720394857230";
char tmp = bigNumber.at(5);
int digit = atoi(&tmp);
int digit2 = atoi(&bigNumber.at(5))
int digit3 = atoi(&bigNumber.at(12));
std::cout << "digit: " << digit << std::endl;
std::cout << "digit2: " << digit2 << std::endl;
std::cout << "digit3: " << digit3 << std::endl;
}
これにより、次の出力が生成されます。
数字:7
digit2:2147483647
digit3:57230
最初の結果は望ましい結果です。 2番目のものは、文字列で見つけることができない乱数のように思えます。 3番目の文字列は文字列の末尾ですが、予想どおり1桁ではなく、12番目のインデックスから文字列の末尾までです。誰かが私にさまざまな出力を説明できますか?
編集:これは許容できる解決策でしょうか?
char tmp[2] = {bigNumber.at(5), '\0'};
int digit = atoi(tmp);
std::cout << "digit: " << digit << std::endl;
解決
それは多かれ少なかれ説明可能です。
int main(){
std::string bigNumber = "93485720394857230";
この行は、単一の文字「5」を文字変数にコピーします。 atoi
はこれを正しく変換します。 atoi
は、文字列パラメーターが有効な0で終わる文字列であることを想定しています。 &amp; tmp
は文字変数へのポインタにすぎません-メモリ内の文字の直後のメモリが不明であるため、この呼び出しの動作は未定義です。正確には、nullで終了する文字列を作成して渡す必要があります。*
char tmp = bigNumber.at(5);
int digit = atoi(&tmp);
この行は、文字列の位置5の文字へのポインターを取得します。これは、上記の元の大きな数字の文字列へのポインタであるため、 atoi
の文字列パラメータは文字列「5720394857230」のようになります。 atoi
は、32ビット整数がこれを保持しないため、明らかにこれを整数に変換しようとしています。
int digit2 = atoi(&bigNumber.at(5))
この行は、位置12の文字列へのポインタを取得します。 atoi
へのパラメータは文字列です
「57230」。これは、整数57230に正しく変換されます。
int digit3 = atoi(&bigNumber.at(12));
... }
C ++を使用しているため、文字列を整数に変換するより優れた方法があります。私が不満なのはBoost lexical_castライブラリです。次のように使用します:
char tmp = bigNumber.at(5);
// convert the character to a string then to an integer
int digit = boost::lexical_cast<int>(std::string(tmp));
// this copies the whole target string at position 5 and then attempts conversion
// if the conversion fails, then a bad_lexical_cast is thrown
int digit2=boost::lexical_cast<int>(std::string(bigNumber.at(5)));
*厳密には、 atoi
は、数字以外の数字が見つかるまで数字をスキャンします。無効なメモリの場所を読み取った場合とそれがどうなるかは、明らかに定義されていません。
他のヒント
2番目の数字が表示される理由はわかっています。
正しい値が表現可能な値の範囲外の場合、
INT_MAX
またはINT_MINが返されます。
2147483647はINT_MAX
bigNumber.at()
は、1文字の新しい文字列ではなく、文字列内の文字のアドレスを返します。したがって、2番目の呼び出しは実際には:
atoi("720394857230")
これにより、内部アルゴリズムがオーバーフローします。
また、最初の呼び出しは(&amp; tmp)+1
のメモリ内の(ランダムな)値に依存するため、非常に危険です。
2文字の文字列を割り当て、 bigNumber.at()
の最初の文字と \ 0
の1文字を2番目の文字に割り当ててから、< code> atoi()に一時的な文字列のアドレスを指定します。
atoi
の引数は、ゼロで終わる文字列でなければなりません。
関数 at
は、文字列内のcharへのポインタを提供します。関数 atoi
は、文字を1文字だけでなくintに変換します。