itoa函数,考虑当待处理整数为-2^(字长-1)的情况

     源自《The C Programming Language》 P53 pr3-4,代码位于ex3.6中:

     在数的对二的补码表示中,我们编写的itoa函数不能处理最大的负数,即n等于-(2^(字长-1))的情况。请解释原因,

     修改函数使得它在任意机器上运行时都能得到正确结果。

     代码:

     

main.c
1 #include <stdio.h>
2 #include <string.h>
3
4 #define MAXLINE 100
5
6 void itoa(int n, char s[],int width);
7 void itob(int n, char s[], int b);
8 void reverse(char s[]);
9
10 int main()
11 {
12
13 int num;
14 char res_str[MAXLINE];
15
16 num = -214;
17 //itoa(num, res_str, 8);
18 itob(num, res_str, 16);
19 printf("%s\n", res_str);
20
21 return 0;
22 }
23
24 void reverse(char s[])
25 {
26
27 int i, j;
28 char temp;
29
30 for(i = 0,j = strlen(s)-1; i < j; ++i,--j) //注意:别写成j = strlen(s)了
31 {
32 temp = s[i];
33 s[i] = s[j];
34 s[j] = temp;
35 }
36
37 }
38
39 /*void itoa(int n, char s[])
40 {
41
42 int flag;
43 int i;
44
45 flag = 1;
46 i = 0;
47 if(n < 0)
48 {
49 n = -n;
50 flag = -1;
51 }
52 do
53 {
54 s[i++] = n % 10 + '0';
55 }while((n /= 10) > 0);
56 if(flag == -1)
57 s[i++] = '-';
58 s[i] = '\0';
59 reverse(s);
60
61 }
62 */
63
64 /*********************************************************************
65 itoa参考代码
66 *********************************************************************/
67
68 void itoa(int n, char s[], int width) //优点:可以处理-(2^(字长-1))这种情况
69 {
70 int sign;
71 int i;
72 int j;
73
74 sign = n;
75 i = 0;
76 do
77 {
78 s[i++] = abs(n % 10) + '0';
79 }while((n /= 10) != 0); //不写成(n /= 10) > 0是考虑到n为负数的情况
80 if(sign < 0)
81 s[i++] = '-';
82 j = width - i;
83 if(j > 0)
84 while(j > 0)
85 {
86 s[i++] = ' ';
87 --j;
88 }
89 s[i] = '\0';
90 reverse(s);
91
92 }
93
94 /*void itob(int n, char s[], int b)
95 {
96 int sign;
97 int i;
98 int m;
99
100 sign = n;
101 i = 0;
102 do
103 {
104 switch(m = abs(n % b))
105 {
106 case 0: case 1: case 2: case 3: case 4:
107 case 5: case 6: case 7: case 8: case 9:
108 s[i++] = m + '0';
109 break;
110
111 case 10:
112 s[i++] = 'A';
113 break;
114
115 case 11:
116 s[i++] = 'B';
117 break;
118
119 case 12:
120 s[i++] = 'C';
121 break;
122
123 case 13:
124 s[i++] = 'D';
125 break;
126
127 case 14:
128 s[i++] = 'E';
129 break;
130
131
132 case 15:
133 s[i++] = 'F';
134 break;
135
136 default:
137 break;
138 }
139 }while((n /= b) != 0);
140 if(sign < 0)
141 s[i++] = '-';
142 s[i] = '\0';
143 reverse(s);
144
145 }*/
146
147 /*********************************************************
148 itob参考代码
149 *********************************************************/
150 void itob(int n, char s[], int b)
151 {
152 int sign;
153 int i;
154 int m;
155
156 sign = n;
157 i = 0;
158 do
159 {
160 m = abs(n % b);
161 s[i++] = (m <= 9) ? m + '0' : m - 10 + 'A'; //较之于上面的代码,这样很简洁
162 }while((n /= b) != 0);
163 if(sign < 0)
164 s[i++] = '-';
165 s[i] = '\0';
166 reverse(s);
167 }

   分析:

     1,  原因:对于整数的对二补码表示中,所能表示的最大整数值为2^(字长-1) - 1,故不能通过n = -n;

                   将-(2^(字长-1))转化为2^(字长-1),而是通过abs宏取绝对值的方法abs(n % 10)得到,

                   比如n = -2147483648(即-(2^(字长-1)),通过abs(n % 10)得到8,这样就绕过了上述

                   的问题。

     2,  参考代码的重点:

                   (a):用abs(n % 10)而非n = -n来规避当n为最小整数(-2147483648)时。

                   (b):do-while循环的判断条件用((n / 10) != 0)而非((n / 10) > 0)来避免当n是个负数时

                           使itoa函数陷入无限循环汇总。

posted on 2011-05-25 23:52  将军之盾  阅读(403)  评论(0编辑  收藏  举报