整型和字符数组之间的转换(略带进制的转化)(一)

2014-11-24 02:56:56 · 作者: · 浏览: 4
C语言和python语言不同,C语言有严格的输入控制,所以类型很清晰,python的类型,一般输入的都是字符串类型的。要用的时候就直接转换一下,很方便。没有太多限制,但是我们在实现C语言类型转换的时候,一个是程序执行的时候有一个隐式的转换,那个是在同一种类型下,比如int 和long的转换,int和double的转换,这种向上的转换,这样的系统自己帮我们做了。还有一种强制的转换,我们想把float的类型变成int类型的。那就加上一个 (int) 要转换的数 ,我们发现这些是在同时数值情况下的一种转换。C语言里面也有字符类型char,这个类型很灵活,因为在 c语言里面没有字符串这个类型,而我们从一个文本里面读取一个数据的时候,往往将读取到的数据保存在一个字符数组里面,然后通过这样的一个处理,将其变成一个字符串的形式。那么当我们想要操作字符串里面的那些个数的时候,要把他们当作数来计算的时候,我们就不能用强制转换这一类的方法了。简化的说就是将字符的类型转换成数字类型,在标准库里面,有一个atoi 的函数,它包含在头文件stdlib.h里面。我们可以调用他,但是我们有时不仅仅是只是要将他转换成int类型,可能还有其他的类型,或是将字符型转换成整型等。下面就是一些具体的函数实现。
atoi
我们首先判断,所个的字符串里面的字符是不是在‘0’-‘9’之间的字符,不是的话,那就没有什么可以转换的必要了,这是一个先决的条件。有了这个的保证,那么我们就是要看这个字符有几位。好比‘8024’ 四位数,我们知道在10进制中,对应的位置可以用乘上10次幂就好,那么现在们可以这么想,用字符的长度作为循环的条件,对于最高位我们可以将其多次乘上10,就可以做到将数字对到10进制数的对应位置。字符的数字‘1’是不可以用作数值1来和整型数运算的,我们同样要转换一下,在ascii码里面,‘1’代表是49,‘0’代表是48,看出来没? 只要拿字符‘1’减去‘0’。
函数实现:
复制代码
1 int atoi(char s[])
2 {
3 int i,n;
4
5 n = 0;
6 for( i = 0;a[i] >='0' && a[i] <= '9';i++)
7 n = n * 10 + (s[i] - '0');
8 return n;
9 }
10
复制代码
看上去很简单的样子,其实这个函数有很多的局限性,比如无法对带符号的字符串进行转换,以及对空格的回车符的处理等,功能还是不太全的,那考虑将他加上去把。那就是加上对符号的判断。这个应该是很好实现的。下面实现下。
复制代码
1 int atoi(char s[])
2 {
3 int i,n,sign;
4 for(i = 0; isspace(s[i]);i++)
5 ;
6 sign = (s[i] == '-') -1:1;
7 if(s[i] == '+' || s[i] == '-')
8 i++;
9 for(n = 0; isdigit(s[i]);i++)
10 n = n*10 + (s[i] - '0');
11 return sign * n;
12 }
复制代码
在上面的那个函数上,用到了里面的两个函数,isspace和isdigit 从字面上看的出来,一个是判断空白字符的一个是判断字符数字的。这样可以简化一些代码,功能和第一个函数里面for 的功能一样的。回到这个函数,有了对符号的处理,能够输出一个带符号的数了。这个是在上面的函数上的一个提升,对于哪些恶意的输入,是在没办法识别,比如输入-9 0,这个就不能判断出了,哪有数字是这样的。但是对于数字本身,因为是int类型的,所以数的大小有约束,可以考虑考虑将这边优化下。
同样,我们能将字符类型的转为int的,反过来可不可以?这个必须可以的。我们简单分析下,如果要将一个数字转为一个字符,我们得现将这个数分解出来,把每个位上的数取出来,这个有一个套路的,这边很简单的就可以实现。然后就是对数字的正负符号的一个考虑,这个可以通过判断数的正负来解决。下面就是简单的实现下这个函数。
itoa:
复制代码
1 void itoa(int n,char s[])
2 {
3 int i,sign;
4
5 if((sign = n) < 0)
6 n = - n;
7 i = 0;
8 do
9 {
10 s[i++] = n%10 + '0';
11 }while((n/=10) > 0);
12
13 if(sign < 0)
14 s[i++] = '-';
15 s[i] = '\0';
16 reverse(s); //自编函数,实现数组的逆序。在后面实现
17 }
复制代码
引入另一个变量,保存原来的数,用来判断正负,对于一开始将n变号的那个操作,是简化了后面循环里面的操作,不然还要判断一下这个数的正负,比较麻烦。最后的那个reverse函数,是将这个数组逆序,我们是将这个数变成了一个字符串,可以简化的用%s将其输出,而我们保存的时候是逆序的就是个位上的数在前面,那就把数组再此逆序,还原成正常的顺序。
问题来了,我们发现最小的负数如果用n= -n这个来处理的话,是要出错的,最大的正数(对二补码中)比最小负数的绝对值小1,如果直接转换,那就会出现溢出状况,这个就不是太好的,那就要我们改下,让函数更加的完善。改动的地方就是n=-n,不能这么做了,那就不变,直接拿原来的数操作。我们这边用到宏定义。
解决方案:
复制代码
#define abs(x) ((x)< 0 -(x):(x)) //n%10的值进行判断,保证是正的。
void itoa(int n,char s[])
{
int i,sign ;
sign = n;
i = 0;
do
{
s[i++] = abs(n%10) +'0';
}while((n/=10) != 0);
if(sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
复制代码
  通过宏定义的一个绝对值函数,将取位的操作转换为正的,保证程序正确运行。这边也有一个比较重要的一点就是,循环的结束条件,因为有了负数,我们不能再用">0"来判别结束了,不然就是一个死循环了。改动的也就是这两个部分。这样对对二补码运算的一个支持把。函数到这边了,应该差不多了,不过我们可以再加一个小的功能,控制一个输出,输出的长度。这就多了一个参数。这个改动有一定的好处。下面是改后的代码:
复制代码
void itoa(int n,char s[],int w)
{
int i,sign ;