2011-10-24 9 views
6

誰かがこれらの呼び出しが同じ結果を返さない理由を説明できますか?atoiを使用した結果が異なります

unsigned int GetDigit(const string& s, unsigned int pos) 
{ 
     // Works as intended 
     char c = s[pos]; 
     return atoi(&c); 

     // doesn't give expected results 
     return atoi(&s[pos]); 
     return atoi(&static_cast<char>(s[pos])); 
     return atoi(&char(s[pos])); 
} 

備考:私はintcharを変換するための最良の方法を探していませんよ。あなたの試みの

+0

あなたが期待しているヌルで終了する文字列の代わりに '' char''を 'atoi'に渡すので、"意図した通りに動作します "という結果がUBにあります。 –

+0

@ littadadv:確かに、私は*ポインタを1つの 'char'に意味しました。あなたが 'atoi'アクセスメモリを"配列 "の最後の要素を越えて作っているので、スタックに続くものの保証がないので、単一のcharへのポインタを渡すことは確かにUBです")。 –

+1

@Matteo: 's [pos]'が0バイトでなければ、それ以外の場合は 'atoi'が読み込みを停止させるような文字ではありません;-) –

答えて

10

なし1(それだけで事故によって動作するように起こった)「ことを目的として作品」を含め、正しいません。初心者の方は、atoi()にはNULで終了する文字列が必要です。

方法以下について:

unsigned int GetDigit(const string& s, unsigned int pos) 
{ 
     return s[pos] - '0'; 
} 

これは、あなたがs[pos]は、有効な小数点以下の桁であることを知ってことを前提としています。そうしないと、エラーチェックが順番に行われます。

+0

' atoi'は最初の文字それは数字の一部として認識できないということです。これはヌル文字である可能性があります。だから、実際にはヌル文字が間違いなく必要ではないように聞こえるでしょうか?しかし、あなたは正しいですが、私の解決策のどれも正しいものではありません。 –

+0

@RonaldMcBean:終端文字は、何が起こっても、文字列の末尾を読み取ることは未定義の動作なので、文字列の一部でなければなりません。 – NPE

0

あなたはC文字列としてデータにアクセスしたい場合は - s.c_str()を使用して、atoiにそれを渡します。

atoiは、Cスタイルの文字列が必要です。std::stringは、動作と特性が異なるC++クラスです。初心者にとっては、NULLで終了する必要はありません。

0

atoiはそれの引数にcharへのポインタを取ります。 char cを使用しているときの最初の試行では、1つの文字へのポインタしかないので、必要な答えが得られます。しかし、あなたが得るものはcharの文字列の始まりであったcharへのポインタです。したがって、後で試みるときにatoiの後に何を得ているのかは、posの文字から変換された数値です。 pos+1,pos+2およびs文字列の最後までです。

1

int atoi(const char* s)は文字フィールドへのポインタを受け入れるので、最後の3回の使用では、& [s]で始まる連続する数字に対応する数字が返されます。それはstd::string内のデータが、NULLで終了するを要求されないので、答えはいくつかの実装上の何か他のもの、すなわち、未定義の動作可能位置0から始まる、"123"のような文字列のために123を与えることができます。

あなたの「作業」アプローチは、未定義の動作を使用しています。 それは別の場所にコピーs[pos]ので他の試みとは異なります。 文字cの隣にあるメモリ内の隣接バイトが誤ってゼロまたは非数字の文字になることが保証されていない限り、動作しているようです。だから@aixの助言に従ってください。部分文字列とは対照的に、あなたが本当にその位置から開始と終了(位置に文字列に1つだけの文字を変換したい場合は

char c[2] = { s[pos], '\0' }; 
return atoi(c); 
0

では、次の操作を行うことができ、それが実際に動作させるために、文字列の最後に)、次のようにすることができます。

int GetDigit(const string& s, const size_t& pos) { 
    return atoi(string(1, s[pos]).c_str()); 
} 

int GetDigit2(const string& s, const size_t& pos) { 
    const char n[2] = {s[pos], '\0'}; 
    return atoi(n); 
} 

たとえば、

3

std::stringを使用しています。内部表現から1文字を取り出して、atoiにポインタを送ります。const char*はNULLで終了する文字列を指します。 std::stringは文字の格納が保証されていないので、ゼロが終了しています。これはあなたのC++実装がこれを行うと思われることだけです。

std::stringにはs.c_str()を使用してコンテンツのゼロ終了バージョンを問い合わせてから、atoiにポインタを使用して呼び出します。

あなたのコードは別の問題が含まれていatoiが署名intを返しながら、あなたは、unsigned intatoiの結果をキャストしています。 あなたの文字列が "-123"の場合

+0

+1:他の問題とすてきな説明を指摘するため –

関連する問題