练习 3-4 在数的对二的补码表示中,我们编写的itoa函数不能处理最大的负数,即n等于-2^(字长-1)的情况。请解释其原因。修改该函数,使它在任何机器上运行时都能打印出正确的值。

来源:互联网 发布:win10的80端口被占用 编辑:程序博客网 时间:2024/06/08 15:41

在原文中的itoa函数为:

/* itoa: convert n to characters in s */void itoa(int n, char s[]){int i, sign;if ((sign = n) < 0) /* record sign */n = -n; /* make n positive */i = 0;do { /* generate digits in reverse order */s[i++] = n % 10 + '0'; /* get next digit */} while ((n /= 10) > 0); /* delete it */if (sign < 0)s[i++] = '-';s[i] = '\0';reverse(s);}

我们知道,最大负数的二进制形式是10000……,在上面的函数itoa中,对最大负数进行n=-n运算时,只改变其符号位,我们可以看到n将会变成0,这样会得到错误的结果,这种情况下,我们可以将这个最大的负数变为无符号数,即n=(unsigned)n,这样子的话,这个无符号数的绝对值等于原来的最大负数的绝对值。为了解决这个问题,我们需要在最开始的位置对最大的负数进行识别并处理,剩下的程序部分不需要改变,直接照搬就行。

判别最大负数的方法有很多,利用它的特殊性质就可以了。比如,一,如果是负数的话,进行减一处理,得到的差如果大于零,说明他就是最大负数;二将这个最大负数变为无符号数,然后进行左移运算,得到结果为0的话,说明这个数就是最大负数。

#include <stdio.h>#include <limits.h>void itoa1(int n, char s[]);//这是改进后可以将最大负数正常输出的函数void itoa2(int n, char s[]);//这是原文中的函数,在输出最大负数时会出现错误void reverse(char s[]);int main(){    int n=INT_MIN;    char s[100];    itoa2(n,s);    for(int i=0;s[i]!='\0';++i){        printf("%c",s[i]);    }    printf("\n");    n=INT_MIN;    itoa1(n,s);    for(int i=0;s[i]!='\0';++i){        printf("%c",s[i]);    }    return 0;}void itoa1(int n, char s[]){int i=0;int sign=n;unsigned n_copy;if ((sign=n)<0){    if((n-1)>0){        n_copy=n;    }else{        n_copy = -n;     }}else{    n_copy=n;}do { s[i++] = n_copy % 10 + '0'; } while ((n_copy /= 10) > 0);if (sign < 0)s[i++] = '-';s[i] = '\0';reverse(s);}void itoa2(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;    for(i=0;s[i]!='\0';++i){        ;    }    --i;    for(int j=0;i>j;--i,++j){        char temp=s[i];        s[i]=s[j];        s[j]=temp;    }}

执行结果如下图所示:
这里写图片描述

阅读全文
0 0
原创粉丝点击