3-4 在数的对二的补码表示中,我们编写的itoa函数不能处理最大的负数,即n等于-(2的(字长-1)次方)。请解释原因,修改函数,使它在任何机器上运行时都能打印出正确的值。
答:最大的负数是指8-bit表示中的-128,用补码表示是10000000。当然,1000 0000是原码时候表示-0,但是00000000也可以表示0,所以把10000000设定为-128的原码,即8-bit表示补码时的范围是-128~127,正好256个数。在书本中p52的itoa(),当n是负数时,n=-n,直接限定n不能等于-128;那么为何n=-n?因为后面的循环条件是while((n/=10)>10)。为了不用n=-n,我们改为while(n/10)这样无论n是正负数,当n为个位后,n/10都是0,不满足循环条件。
以上思路均来自答案。但是我用递归调用实现itoa(),即整数转换为字符串。递归有一个好处是不用reverse()函数。
#include <stdio.h>
#include <stdlib.h>
#include<limits.h>
#include <string.h>
#define MAX 15
int itoa(int,int,char*);
int main(void)
{
int i,location=0;
char s[MAX];
printf("INT_MIN=%d\n", INT_MIN);
location = itoa(INT_MIN, location, s);
s[location] = '\0';
puts(s);
getchar();
return 0;
}
int itoa(int N,int location,char* s)
{
if (N == 0)
{
return location;
}
location = itoa(N / 10, location,s);
if (N<0&&location==0)
{
s[location++] = '-';
}
s[location++] = abs(N % 10) + '0';
if (location == MAX - 1)
{
printf("The num has exceed the maximum of string!\n");
getchar();
exit(0);
}
return location;
}
3-5就是把上面的功能实现为任意进制。主要在于什么时候用数字字符,什么时候用字母字符,以及字母字符的转换。
#include <stdio.h>
#include <stdlib.h>
#include<limits.h>
#include <string.h>
#define MAX 15
#define STEP 16
int itoa(int,int,char*,int );
int main(void)
{
int i,location=0;
char s[MAX];
printf("INT_MIN=%d\n", INT_MIN);
location = itoa(-5000, location, s,STEP);
s[location] = '\0';
puts(s);
getchar();
return 0;
}
int itoa(int N,int location,char* s,int step)
{
int a;
if (N == 0)
{
return location;
}
location = itoa(N / step, location, s, step);
if (N<0&&location==0)
{
s[location++] = '-';
}
if ((a=N%step)<10)
s[location++] = abs(N % step) + '0';
else
s[location++] = abs(N % step) + 'a' - 10;
if (location == MAX - 1)
{
printf("The num has exceed the maximum of string!\n");
getchar();
exit(0);
}
return location;
}