问题描述
在数的反码表示中,上述的 itoa 函数不能处理最大的负数,即 n 等于-2^(字长-1) 的情况。请解释其原因。修改该函数,使它在任何机器上运行时都能打印出正确的值。
问题分解
- 主函数main
- 核心函数 itoa(n, s)。先来看原文的函数实现:
void itoa(int n, char s[])
{
int i, sign;
if((sign = n) < 0){
n = -n;
}
i = 0;
do{
s[i++] = n % 10 + '0';
}while((n /= 10) > 0);
if(sign < 0){
s[i++] = '-';
}
s[i] = '\0';
reverse(s);
}
先来分析itoa函数为什么不能处理最大的负数,我们假设在int数据取值范围位-128 ~ 127 的机器上,当n = -128时,-n = 128 > 127,此时灾难发生了——得到的结果并不是我们想要的字符串。因此,问题处在 if((sign = n) < 0) 这句,那么我们只要将其改造一下即可。
代码实现
#include<stdio.h>
void itoa(int n, char s[]);
void itoa2(int n, char s[]);
void reverse(char s[]);
int main()
{
int n = (~0U >> 1) + 1;
char s[100], s1[100], s2[100];
printf("The input number is: %d\n", n);
itoa(n, s);
printf("The output string of itoa is: %s\n", s);
itoa2(n, s1);
printf("The output string of itoa2 is: %s\n", s1);
return 0;
}
void itoa2(int n, char s[])
{
int sign, i;
sign = n;
i = 0;
do {
s[i++] = ((sign < 0) ?-(n % 10) : n % 10) + '0'; //负数对10求余仍然是负数
} while ((n /= 10) != 0);
if (sign < 0)
s[i++] = '-';
s[i] = '\0';
reverse(s);
}
void itoa(int n, char s[])
{
int i, sign;
if((sign = n) < 0){
n = -n;
}
i = 0;
do{
s[i++] = n % 10 + '0';
}while((n /= 10) > 0);
if(sign < 0){
s[i++] = '-';
}
s[i] = '\0';
reverse(s);
}
void reverse(char s[])
{
int i, j, c;
for (j = 0; s[j] != '\0'; j++)
;
for (i = 0, j--; i < j; i++, j--)
{
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
编译运行
由运行结果可看出,原方法得到的结果不是预期的,改造后的得到了正确的结果。