3

I have a function print_number.

The function checks if in front of the number there exists '-', then it reverse the number and takes every digit and prints it. The algorithm works pretty good but if i give -2.147.483.648 ( which should be the bottom limit of an integer ) it pritns -0 and i don't know why.

#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;
    }
}
6
  • Care to use a debugger? ;p Commented Aug 13, 2017 at 14:20
  • 1
    See this Commented Aug 13, 2017 at 14:23
  • 1
    You can't negate INT_MIN in a two's-complement system (using nr *= -1;) because the value has no representation. The loop while(nr > 9) will not iterate. Commented Aug 13, 2017 at 14:23
  • I unterstood. Thanks so much Commented Aug 13, 2017 at 14:27
  • Looks like you're converting the positive version of the input. There is no value +2.147.483.648 in a 32-bit signed 2s complement int. The highest value is 2.147.483.647 Commented Aug 13, 2017 at 14:28

3 Answers 3

1

When you are doing

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

It inverses negative number to the positive one. If you will run it for -2.147.483.648, you will receive

nr = 2.147.483.648 // == binary 1 0000000000000000000000000000000

As INT is 32 BIT variable in your architecture (and at least 16 BIT variable by the spec), so '1' overflows it and so on

nr = 0 // For gcc-like C realisation

And accepting the ISO9899 spec, this behaviour of signed int overflow is realisation-specified thing and may not be predicted in common.

Use long long value if you're needing to use your program for larger values. Something like:

#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);
}

And test:

> gcc test.c
> ./a.out 
-2147483648
Sign up to request clarification or add additional context in comments.

18 Comments

How will long help? Did you mean long long?
INT_MIN * -1 causes an overflow and the result is undefined.
No, "long int" is enougth, see the demo I\ve attached on post update. long int makes variable twice larger than without long, so on it's enougth to store +2147483648 value.
About undefined - yes, you are particularry right, but in really it will be calculated for 32 bits, so we can predict that it will be zero (1[overflow] 000...000[32 zeros]).
No, it is undefined, so nothing can be "predicted". a 32-bit int cannot hold 33 bits. Your code prints-0. And sizeof(long) is 4 on my system, hence my remark about using long long.
|
1

Firstly, the MAX and MIN range for an INT are -2,147,483,648 and 2,147,483,647 respectively.
Negating -2,147,483,648 means a positive value 2,147,483,648 would result in an overflow by 1 as it is out of bounds for the MAX range. This operation will result in the same value of -2,147,483,648.

Secondly, you might encounter an overflow during the integer reversing process.
Example, reversing 2147483647 causes an overflow after the intermediate result of 746384741.
Therefore, you should handle that by throwing an exception or returning 0.

Thirdly, your loop for reversing the number is inaccurate. It should loop till while(nr != 0)

Here's the complete code.

#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);
}

1 Comment

"Firstly, the MAX and MIN range for an INT are -2,147,483,648 and 2,147,483,647 respectively. " --> C does not specify that.
0

nr *= -1; is a problme when nr == INT_MIN as that is signed integer overflow. The result is undefined behavior (UB). Best to avoid.

Wider integers are not always available.

Using OP's general, approach, do not change the sign of nr until it is reduced.

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;
  }
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.