您的位置:首页 > 其它

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

2011-05-25 23:52 483 查看
源自《The C Programming Language》 P53 pr3-4,代码位于ex3.6中:

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

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

代码:

main.c

#include <stdio.h>
#include <string.h>

#define        MAXLINE        100

void itoa(int n, char s[],int width);
void itob(int n, char s[], int b);
void reverse(char s[]);

int main()
{

int num;
char res_str[MAXLINE];

num = -214;
//itoa(num, res_str, 8);
itob(num, res_str, 16);
printf("%s\n", res_str);

return 0;
}

void reverse(char s[])
{

int i, j;
char temp;

for(i = 0,j = strlen(s)-1; i < j; ++i,--j)    //注意:别写成j = strlen(s)了
{
temp = s[i];
s[i] = s[j];
s[j] = temp;
}

}

/*void itoa(int n, char s[])
{

int flag;
int i;

flag = 1;
i = 0;
if(n < 0)
{
n = -n;
flag = -1;
}
do
{
s[i++] = n % 10 + '0';
}while((n /= 10) > 0);
if(flag == -1)
s[i++] = '-';
s[i] = '\0';
reverse(s);

}
*/

/*********************************************************************
itoa参考代码
*********************************************************************/

void itoa(int n, char s[], int width)    //优点:可以处理-(2^(字长-1))这种情况
{
int sign;
int i;
int j;

sign = n;
i = 0;
do
{
s[i++] = abs(n % 10) + '0';
}while((n /= 10) != 0);    //不写成(n /= 10) > 0是考虑到n为负数的情况
if(sign < 0)
s[i++] = '-';
j = width - i;
if(j > 0)
while(j > 0)
{
s[i++] = ' ';
--j;
}
s[i] = '\0';
reverse(s);

}

/*void itob(int n, char s[], int b)
{
int sign;
int i;
int m;

sign = n;
i = 0;
do
{
switch(m = abs(n % b))
{
case 0: case 1: case 2: case 3: case 4:
case 5: case 6: case 7: case 8: case 9:
s[i++] = m + '0';
break;

case 10:
s[i++] = 'A';
break;

case 11:
s[i++] = 'B';
break;

case 12:
s[i++] = 'C';
break;

case 13:
s[i++] = 'D';
break;

case 14:
s[i++] = 'E';
break;

case 15:
s[i++] = 'F';
break;

default:
break;
}
}while((n /= b) != 0);
if(sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);

}*/

/*********************************************************
itob参考代码
*********************************************************/
void itob(int n, char s[], int b)
{
int sign;
int i;
int m;

sign = n;
i = 0;
do
{
m = abs(n % b);
s[i++] = (m <= 9) ? m + '0' : m - 10 + 'A';    //较之于上面的代码,这样很简洁
}while((n /= b) != 0);
if(sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}


  分析:

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函数陷入无限循环汇总。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐