2011-10-24 76 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])); 
} 

備註:我不是在尋找一個char轉換爲int的最佳途徑。

+0

由於您傳遞給'atoi'單個'char'而不是它所期望的以null結尾的字符串,因此「按預期工作」會導致UB。 –

+0

@littleadv:當然,我的意思是指向一個char的*指針;並且傳遞一個指向單個字符的指針肯定是UB,因爲你不能保證它跟在堆棧後面(實際上,它是UB毫無疑問是因爲你正在使'atoi'訪問內存超過「數組的最後一個元素「)。 –

+1

@Matteo:毫無疑問,除非'[pos]'恰好是0字節,否則會導致'atoi'停止讀取的字符;-) –

回答

10

您的任何嘗試都是正確的,包括「按預期工作」(這只是偶然的工作)。對於初學者,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時,它只需要指向一個字符的指針,因此您可以得到您想要的答案。然而在其他嘗試中,您得到的是指向char的指針,該指針恰好是一串char s的開始,因此我假設atoi後面的內容是後面的嘗試是從位置pos中的字符轉換而來的數字, pos+1,pos+2並且直到s字符串的末尾。

1

由於int atoi(const char* s)接受指向字符字段的指針,因此您最後三次使用時返回的數字對應於從& s [pos]開始的連續數字,例如,它可以爲從012開始的字符串如"123"提供123.由於std::string內的數據不是所需的以空終止,所以在一些實現中,答案可以是其他任何內容,即未定義的行爲。

您的「工作」方法也使用未定義的行爲。 它與其他嘗試不同,因爲它s[pos]的值複製到另一個位置。 只有在字符c旁邊的內存中的相鄰字節意外地發生爲零或非數字字符時,它似乎才起作用,這是不能保證的。所以請按照@aix給出的建議。

要使它真正發揮作用,你可以做到以下幾點:

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,從它的內部表示中獲取一個字符並將它的指針送入atoi,該指針需要一個指向NULL結尾字符串的const char*。不保證std::string存儲字符,以便終止零,這只是運氣,你的C++實現似乎這樣做。

正確的方法是使用s.c_str()std::string索取零終止版本的內容,然後使用指向它的指針atoi

您的代碼包含另一個問題,你是鑄造的atoi結果到unsigned int,而atoi返回簽署int如果你的字符串是「-123」

+0

+1:指出另一個問題和一個很好的解釋 –