atoi是C标準庫提供的一個接口,函數原型大緻為:
int atoi(const char* pch);
不考慮太多異常情況,可以這樣實作:
int atoi(const char* pch)
{
if (NULL == pch)
{
return 0;
}
int iSymbol = 1;
if (*pch == '-')
{
iSymbol = -1;
++pch;
}
int num = 0;
//周遊字元串
while (*pch != '\0')
{
if (*pch>= '0' && *pch<='9')
{
num = 10*num + *pch++ - '0';
}
else
{
break;
}
}
return num;
}
我們知道,數字 + 字元0,可以得到其對應的字元,比如
1 + '0' == '1' 對應可以得出 '1' - '0' == 0
C标準庫未提供itoa這個接口,但很多編譯器都有提供(比如vs就在stdlib.h中聲明了),應用也比較廣泛,一般聲明為:
char* itoa(int _Val, char * _DstBuf,int _Radix);
不考慮太多異常情況,大緻可以這樣實作:
char* itoa(int _Val, char * _DstBuf,int _Radix)
{
//隻支援2、8、10、16進制
if(_Radix != 10 && _Radix != 16 && _Radix != 8 && _Radix != 2)
{
_DstBuf = '\0';
return _DstBuf;
}
//每個進制每位對應的字元
char index[]="0123456789ABCDEF";
int i=0;
int j = 0;
int k = 0;
unsigned unum = 0;;
//10進制負數
if(_Radix==10 && _Val<0)
{
k=1;
unum=(unsigned)-_Val;
_DstBuf[i++]='-';
}
else
{
unum=(unsigned)_Val;
}
do
{
_DstBuf[i++] = index[unum%(unsigned)_Radix];
unum/=_Radix;
}
while(unum);
_DstBuf[i]='\0';
//反轉字元串
char temp;
for(j=k;j<=(i-k-1)/2;j++)
{
temp=_DstBuf[j];
_DstBuf[j] = _DstBuf[i-1+k-j];
_DstBuf[i-j-1]=temp;
}
return _DstBuf;
}
這裡主要使用了/、%,還有數字/字元轉換,以及字元串反轉,以下大緻解釋下:
比如我調用的時候傳參:
sr::itoa(98521,arr,16);
puts(arr);
意為将98521轉換為16進制
在接口中,使用了index[]定義16進制每位的表現字元,使用下标可以一一對應
按照除16 + 模16,可以得到下面這個表
98521 %16 9
6157 %16 13
384 %16 0
24 %16 8
1 %16 1
最後一列再對應到index數組中的所有,可以得到9D081,反轉後可得到1809D
--------------------------------------------------------華麗麗的分割線---------------------------------------------
其實按照上面那個表,可以獲知,itoa其實也可以通過遞歸實作,而且由于遞歸使用了棧來存儲中間過程設計的變量,遵循後進先出的規則,是以也不需要反轉字元串
下面也大緻實作下,為了友善起見,使用string來存儲:
void itoa(string &str,int in_iNum,int n)
{
//不支援負數
if (in_iNum < 0)
{
in_iNum = -1 *in_iNum;
}
int tmp_iVal = in_iNum/n;
if (tmp_iVal != 0)
{
itoa(str,tmp_iVal,n);
}
char index[]="0123456789ABCDEF";
str.append(1,*(index + in_iNum%n));
}
遞歸很重要的一點是何時結束調用,這裡當tmp_iVal不為0時,遞歸調用自己,意思也就是,當tmp_iVal為0時,結束調用
ps:這裡使用string的一個原因是如果使用char[],還需要關注下标,有個問題是如果再接口中定義變量用作下标變量,實際每次調用,都會是同樣的值
是以這裡不考慮性能問題,直接傳入string,代碼也會稍微整潔易懂些