數字與字串之間的轉換
阿新 • • 發佈:2019-02-14
C語言為我們提供了數字和字串之間的轉換函式,這些函式有很多,常用的有:
整型數轉字串函式itoa():
<pre name="code" class="cpp"><span style="font-size:18px;">char *itoa(int value,char *string,int radix);
//int value 被轉換的整數,char *string 轉換後儲存的字元陣列,int radix 轉換進位制數,如2,8,10,16 進位制等</span>
浮點數轉字串函式gcvt():
字串轉整型數函式atoi():char *gcvt(double value, int ndigit, char *string); //int value 被轉換的浮點數,char *string 轉換後儲存的字元陣列,int ndigit 有效位數
int atoi(const char *nptr);
//const char *nptr 字串首地址,返回值為轉換結果
字串轉浮點數函式atof():
double atof(const char *nptr);
//const char *nptr 字串首地址,返回值為轉換結果
下面通過一組測試用例說明幾個函式的使用方法
在筆試面試過程中,用人單位可能要求我們自己實現這些轉換函式,考慮到複雜度,在這裡我們只實現整型數和字串之間的轉換函式。當然,程式碼不是重點,重點是解決問題的思路。#include <iostream> #include "stdlib.h" using namespace std; int main() { int i = -1234; double d = -1.23456; char *p_dst = new char[16]; char *p_src1 = "-4321"; char *p_src2 = "-4.321"; //itoa()測試 itoa(i, p_dst, 10); cout<<"itoa(): "<<p_dst<<endl; //gcvt()測試 gcvt(d, 4, p_dst); cout<<"gcvt(): "<<p_dst<<endl; //atoi()測試 i = atoi(p_src1); cout<<"atoi(): "<<i<<endl; //atof()測試 d = atof(p_src2); cout<<"atof(): "<<d<<endl; system("pause"); return 0; }
自己的iToa()函式:
實現1:轉換索引表的使用
char* itoa(int num,char *str,int radix) { /*索引表*/ char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; unsigned unum;/*中間變數*/ int i=0,j,k; /*確定unum的值*/ if(radix==10 && num<0)/*十進位制負數*/ { unum=(unsigned)-num; str[i++]='-'; } else unum=(unsigned)num;/*其他情況*/ /*轉換*/ do{ str[i++]=index[unum%(unsigned)radix]; unum/=radix; }while(unum); str[i]='\0'; /*逆序*/ if(str[0]=='-')k=1;/*十進位制負數*/ else k=0; char temp; for(j=k;j<=(i-1)/2;j++) { temp=str[j]; str[j]=str[i-1+k-j]; str[i-1+k-j]=temp; } return str; }
這份程式碼是百度百科上的實現,完全實現了標準itoa函式的功能。採用的是一般的臨時字串加翻轉的方法,這裡邏輯並不是很複雜,值得學習的地方索引表的使用。一般的轉換過程,比如字元數字與整型數字之間、大小寫字母之間的轉換,其轉換規則都是固定的,都可以利用加減一個字元的方法實現。但此處由於ASCII表中9和A並沒有相鄰,所以會存在兩種轉換規則。這時候可以採用轉換索引表的方法,人工組織一個轉換規則。轉換表的構造非常靈活,可以滿足各種各樣的轉換規則。
實現2:遞迴演算法中的引用與非引用
static void do_iToa(int i, char* &a)
{
//功能:將整形數字轉換為字串
//說明:要求字串記憶體已分配
// 傳引用以保證遞迴退出時指標正確偏移
if(i < 0){
*a = '-';
do_iToa(-1*i, ++a);
return;
}
if(i == 0){
return;
}
else{
char tmp_c = i%10 + '0';
do_iToa(i/10, a);
*a = tmp_c;
a++;
}
}
void iToa(int i, char* a)
{
//功能:將整型數轉換為字串
//說明:呼叫遞迴子函式完成轉換,新增'\0'
// 傳值以保證實參指標不發生變化
// 負責指標非空判斷
if(a==NULL){
return;
}
do_iToa(i, a);
*a = '\0';
}
這份程式碼是本人自己實現的,沒有采用上面的臨時字串加翻轉的方法,而是採用了遞迴。在實現過程的主要問題是引數a的向上傳遞,由於無法事先得知數字長度,所以利用遞迴過程中的臨時變數將其一個一個儲存起來,但a所指位置是和長度有關的。所以在遞迴過程中a的移動規則是不能確定的,只有在遞迴返回時才可以移動a,但這就要求a的改變必須可以向上層函式傳遞,否則只是改變了下層a的值,上層的a無法移動就會造成錯誤。
解決辦法就是採用指標引用或者二級指標了,但這樣又會改變實參值,導致呼叫完iToa()後指標引數改變,這對使用者來說簡直是一場噩夢,這裡採用的方法是中間加一層傳值函式,以此來隔離實參。
由於轉換長度有限,這種遞迴貌似有華而不實的嫌疑甚至可能會弄巧成拙,因為遞迴本身的呼叫時間很可能會比那個常數項因子更費時間。但這種設計思路還是值得學習的,一是利用引用向上傳遞引數變化,而是利用入口函式傳值隔離實參。
自己的aToi()函式:
這個函式不存在“回溯”的過程,可以用一次遍歷來解決問題。
int aToi(char *a)
{
//功能:將字串轉換為整數
//說明:字串可以帶"+"、"-"號,預設為正數
int res = 0;
int flag = 1;
if(*a == '-'){
flag = -1;
a++;
}
if(*a == '+'){
a++;
}
while(*a != '\0'){
res *= 10;
res += *a-'0';
a++;
}
return res*flag;
}
最後總結一下:
1. C庫函式itoa()、gcvt()、atoi()、atof()的使用方法
2. 轉換表解決問題的思路
3. 遞歸向上傳引數用引用或二級指標,用入口函式隔離實參
能力有限,如有問題,歡迎各位大神批評指正!