逐位打印整数

3

我有一个名为print_number的函数。

该函数检查数字前面是否存在“ - ”,如果是,则反转该数字并取每个数字进行打印。该算法运行良好,但如果我给出-2.147.483.648(这应该是整数的下限),它会打印出-0,我不知道为什么。

#include<stdio.h>

void    print_char(char character)
{
    printf("%c",character);
}

void    print_number(int nr)
{

    int reverse=0;

    if (nr < 0)
    {
        print_char('-');
        nr *= -1;
    }

    while(nr > 9)
    {
        reverse = reverse * 10 + nr % 10;
        nr = nr / 10;
    }
    print_char(nr + '0');

    while(reverse)
    {
        print_char(reverse % 10 + '0');
        reverse = reverse / 10;
    }
}

你想使用调试器吗?;p - gsamaras
1
请查看此链接 - BLUEPIXY
1
在二进制补码系统中,您无法否定INT_MIN(使用nr *= -1;),因为该值没有表示。循环while(nr > 9)将不会迭代。 - Weather Vane
我明白了。非常感谢。 - nextdarius
看起来你正在转换输入的正版本。在32位有符号2s补码整数中,没有值+2.147.483.648。最高值为2.147.483.647。 - Gene
在执行否定操作之前,将整数转换为相应的无符号类型。 - o11c
3个回答

1
当你在进行编程时,
if (nr < 0)
{
    print_char('-');
    nr *= -1;
}

它将负数反转为正数。如果您对-2.147.483.648运行它,您将收到
nr = 2.147.483.648 // == binary 1 0000000000000000000000000000000

由于你的架构中INT是32位变量(至少按规范为16位变量),所以'1'会导致其溢出,以此类推。

nr = 0 // For gcc-like C realisation

接受ISO9899规范,有符号整数溢出的行为是实现特定的事情,可能无法在常见情况下预测。

如果您需要在程序中使用更大的值,请使用long long值。像这样:

#include<stdio.h>

void    print_char(char character)
{
    printf("%c",character);
}

void    print_number(long long nr)
{
    int reverse=0;

    if (nr < 0)
    {
        print_char('-');
        nr *= -1;
    }

    while(nr > 9)
    {
        reverse = reverse * 10 + nr % 10;
        nr = nr / 10;
    }
    print_char(nr + '0');

    while(reverse)
    {
        print_char(reverse % 10 + '0');
        reverse = reverse / 10;
    }
}

void main(void){
    print_number(-2147483648LL);
}

并测试:

> gcc test.c
> ./a.out 
-2147483648

INT_MIN * -1 会导致溢出,结果未定义。 - Weather Vane
不需要使用“long int”,请查看我在帖子更新中附加的演示。使用“long int”会使变量的大小增加一倍,因此它足以存储+2147483648的值。 - MobDev
关于未定义 - 是的,你说得很对,但实际上它将被计算为32位,因此我们可以预测它将为零(1[溢出] 000...000 [32个零])。 - MobDev
不,它是未定义的,因此无法“预测”。32位的int不能容纳33位。你的代码打印出-0。在我的系统上,sizeof(long)为4,因此我提到使用long long - Weather Vane
好的,所以你需要使用 long long :) - MobDev
显示剩余13条评论

1
首先,INT的最大和最小范围分别为-2,147,483,6482,147,483,647
取反-2,147,483,648意味着正值2,147,483,648会导致溢出1,因为它超出了MAX范围。 此操作将导致相同的值-2,147,483,648
其次,在整数反转过程中可能会遇到溢出。
例如,反转2147483647会在中间结果746384741后导致溢出。
因此,您应该通过抛出异常或返回0来处理它。
第三,您反转数字的循环不准确。 它应该循环直到while(nr != 0) 这是完整的代码。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

int main()
{
    void reverseNumber(int);

    reverseNumber(124249732);
    return 0;
}

void reverseNumber(int nr)
{
    printf("nr = %d\n", nr);

    int reverse = 0;
    bool neg = false;
    if (nr < 0) {
        neg = true;
        nr *= -1;
    }

    while (nr != 0) {
        int digit = nr % 10;
        int result = reverse * 10 + digit;

        if ((result - digit) / 10 != reverse) {
            printf("ERROR\n");
            exit(0);
        }

        reverse = result;
        nr = nr / 10;
    }

    if(neg) {
        printf("%c", '-');
    }
    printf("%d\n", reverse);
}

首先,C语言并没有指定INT类型的最大和最小范围,但通常情况下,INT类型的最大值为2,147,483,647,最小值为-2,147,483,648。 - chux - Reinstate Monica

0

nr *= -1;nr == INT_MIN时是一个问题,因为这是有符号整数溢出。结果是未定义行为 (UB)。最好避免。

更宽的整数并不总是可用的。

使用OP的一般方法,在减少nr之前不要改变符号。

void print_number(int nr) {
  int reverse = 0;

  if (nr < 0) {
    print_char('-');
    //nr *= -1;
  }

  while (nr/10) {   // new test
    reverse = reverse * 10 + nr % 10;
    nr = nr / 10;
  }
  reverse = abs(reverse);  // reverse = |reverse|
  nr = abs(nr);            // nr = |nr|
  print_char(nr + '0');

  while (reverse) {
    print_char(reverse % 10 + '0');
    reverse = reverse / 10;
  }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接