查看匯總:2015軟件水平考試程序員精選題匯總
把字符串轉(zhuǎn)換成整數(shù)
題目:輸入一個表示整數(shù)的字符串,把該字符串轉(zhuǎn)換成整數(shù)并輸出。例如輸入字符串"345",則輸出整數(shù)345。
分析:這道題盡管不是很難,學(xué)過C/C++語言一般都能實(shí)現(xiàn)基本功能,但不同程序員就這道題寫出的代碼有很大區(qū)別,可以說這道題能夠很好地反應(yīng)出程序員的思維和編程習(xí)慣,因此已經(jīng)被包括微軟在內(nèi)的多家公司用作面試題。建議讀者在往下看之前自己先編寫代碼,再比較自己寫的代碼和下面的參考代碼有哪些不同。
首先我們分析如何完成基本功能,即如何把表示整數(shù)的字符串正確地轉(zhuǎn)換成整數(shù)。還是以"345"作為例子。當(dāng)我們掃描到字符串的第一個字符'3'時,我們不知道后面還有多少位,僅僅知道這是第一位,因此此時得到的數(shù)字是3。當(dāng)掃描到第二個數(shù)字'4'時,此時我們已經(jīng)知道前面已經(jīng)一個3了,再在后面加上一個數(shù)字4,那前面的3相當(dāng)于30,因此得到的數(shù)字是3*10+4=34。接著我們又掃描到字符'5',我們已經(jīng)知道了'5'的前面已經(jīng)有了34,由于后面要加上一個5,前面的34就相當(dāng)于340了,因此得到的數(shù)字就是34*10+5=345。
分析到這里,我們不能得出一個轉(zhuǎn)換的思路:每掃描到一個字符,我們把在之前得到的數(shù)字乘以10再加上當(dāng)前字符表示的數(shù)字。這個思路用循環(huán)不難實(shí)現(xiàn)。
由于整數(shù)可能不僅僅之含有數(shù)字,還有可能以'+'或者'-'開頭,表示整數(shù)的正負(fù)。因此我們需要把這個字符串的第一個字符做特殊處理。如果第一個字符是'+'號,則不需要做任何操作;如果第一個字符是'-'號,則表明這個整數(shù)是個負(fù)數(shù),在最后的時候我們要把得到的數(shù)值變成負(fù)數(shù)。
接著我們試著處理非法輸入。由于輸入的是指針,在使用指針之前,我們要做的第一件是判斷這個指針是不是為空。如果試著去訪問空指針,將不可避免地導(dǎo)致程序崩潰。另外,輸入的字符串中可能含有不是數(shù)字的字符。每當(dāng)碰到這些非法的字符,我們就沒有必要再繼續(xù)轉(zhuǎn)換。最后一個需要考慮的問題是溢出問題。由于輸入的數(shù)字是以字符串的形式輸入,因此有可能輸入一個很大的數(shù)字轉(zhuǎn)換之后會超過能夠表示的最大的整數(shù)而溢出。
現(xiàn)在已經(jīng)分析的差不多了,開始考慮編寫代碼。首先我們考慮如何聲明這個函數(shù)。由于是把字符串轉(zhuǎn)換成整數(shù),很自然我們想到:
int StrToInt(const char* str);
這樣聲明看起來沒有問題。但當(dāng)輸入的字符串是一個空指針或者含有非法的字符時,應(yīng)該返回什么值呢?0怎么樣?那怎么區(qū)分非法輸入和字符串本身就是”0”這兩種情況呢?
接下來我們考慮另外一種思路。我們可以返回一個布爾值來指示輸入是否有效,而把轉(zhuǎn)換后的整數(shù)放到參數(shù)列表中以引用或者指針的形式傳入。于是我們就可以聲明如下:
bool StrToInt(const char *str, int& num);
這種思路解決了前面的問題。但是這個函數(shù)的用戶使用這個函數(shù)的時候會覺得不是很方便,因?yàn)樗荒苤苯影训玫降恼麛?shù)賦值給其他整形變臉,顯得不夠直觀。
前面的第一種聲明就很直觀。如何在保證直觀的前提下當(dāng)碰到非法輸入的時候通知用戶呢?一種解決方案就是定義一個全局變量,每當(dāng)碰到非法輸入的時候,就標(biāo)記該全局變量。用戶在調(diào)用這個函數(shù)之后,就可以檢驗(yàn)該全局變量來判斷轉(zhuǎn)換是不是成功。
下面我們寫出完整的實(shí)現(xiàn)代碼。參考代碼:
enum Status {kValid = 0, kInvalid};
int g_nStatus = kValid;
///////////////////////////////////////////////////////////////////////
// Convert a string into an integer
///////////////////////////////////////////////////////////////////////
int StrToInt(const char* str)
{
g_nStatus = kInvalid;
longlongnum = 0;
if(str != NULL)
{
const char* digit = str;
// the first char in the string maybe '+' or '-'
bool minus = false;
if(*digit == '+')
digit ++;
else if(*digit == '-')
{
digit ++;
minus = true;
}
// the remaining chars in the string
while(*digit != '\0')
{
if(*digit >= '0' && *digit <= '9')
{
num = num * 10 + (*digit - '0');
// overflow
if(num>std::numeric_limits::max())
{
num = 0;
break;
}
digit++;
}
// if the char is not a digit, invalid input
else
{
num = 0;
break;
}
}
if(*digit == '\0')
{
g_nStatus = kValid;
if(minus)
num = 0 - num;
}
}
return static_cast(num);
}
討論:在參考代碼中,我選用的是第一種聲明方式。不過在面試時,我們可以選用任意一種聲明方式進(jìn)行實(shí)現(xiàn)。但當(dāng)面試官問我們選擇的理由時,我們要對兩者的優(yōu)缺點(diǎn)進(jìn)行評價。第一種聲明方式對用戶而言非常直觀,但使用了全局變量,不夠優(yōu)雅;而第二種思路是用返回值來表明輸入是否合法,在很多API中都用這種方法,但該方法聲明的函數(shù)使用起來不夠直觀。
最后值得一提的是,在C語言提供的庫函數(shù)中,函數(shù)atoi能夠把字符串轉(zhuǎn)換整數(shù)。它的聲明是int atoi(const char *str)。該函數(shù)就是用一個全局變量來標(biāo)志輸入是否合法的。
相關(guān)推薦:
北京 | 天津 | 上海 | 江蘇 | 山東 |
安徽 | 浙江 | 江西 | 福建 | 深圳 |
廣東 | 河北 | 湖南 | 廣西 | 河南 |
海南 | 湖北 | 四川 | 重慶 | 云南 |
貴州 | 西藏 | 新疆 | 陜西 | 山西 |
寧夏 | 甘肅 | 青海 | 遼寧 | 吉林 |
黑龍江 | 內(nèi)蒙古 |