1. 程式人生 > >數字與字串之間的轉換

數字與字串之間的轉換

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():
char *gcvt(double value, int ndigit, char *string);
//int value 被轉換的浮點數,char *string 轉換後儲存的字元陣列,int ndigit 有效位數
字串轉整型數函式atoi():
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. 遞歸向上傳引數用引用或二級指標,用入口函式隔離實參

能力有限,如有問題,歡迎各位大神批評指正!