数字与字符串之间的转换

C语言为我们提供了数字和字符串之间的转换函数,这些函数有很多,常用的有:

整型数转字符串函数itoa():

char *itoa(int value,char *string,int radix);
//int value 被转换的整数,char *string 转换后储存的字符数组,int radix 转换进制数,如2,8,10,16 进制等
 
  浮点数转字符串函数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 
#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(): "<
在笔试面试过程中,用人单位可能要求我们自己实现这些转换函数,考虑到复杂度,在这里我们只实现整型数和字符串之间的转换函数。当然,代码不是重点,重点是解决问题的思路。

自己的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. 递归向上传参数用引用或二级指针,用入口函数隔离实参

能力有限,如有问题,欢迎各位大神批评指正!

你可能感兴趣的:(杂项)