1

I want to use only studio.h library to convert from decimal number to binary number by using an array to store remainder but the result is not correct, maybe i have problem with memory allocation or return value is wrong, please help me to check it. Thank you so much!

#include <stdio.h>
int  n = 0;
int* DecimalToBinary(int number){
    int a[10];      
    while(number!=0){
        a[n++] = number%2;
        number/=2;
    }
    return a;
}

void main(){

    int *d1 = DecimalToBinary(5);
    int *d2 = DecimalToBinary(10);

    for(int i = n-1 ;i>=0;i--)
        printf(" %d",d1[i]);

    printf("\n");

    for(int i = n-1 ;i>=0;i--)
        printf(" %d",d2[i]);

}
Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448

6 Answers6

8

You return a pointer to a local array. That local array is on the stack, and when the function returns the array goes out of scope and that stack memory will be reused when you call the next function. This means that the pointer will now point to some other data, and not the original array.

There are two solutions to this:

  1. Declare the array in the function calling DecimalToBinary and pass it as an argument.
  2. Create the array dynamically on the heap (e.g. with malloc) and return that pointer.

The problem with method 2 is that it might create a memory leak if you don't free the returned pointer.


As noted by Craig there is a third solution, to make the array static inside the function. However in this case it brings other and bigger problems than the two solutions I originally listed, and that's why I didn't list it.

There is also another serious problem with the code, as noted by Uchia Itachi, and that is that the array is indexed by a global variable. If the DecimalToBinary function is called with a too big number, or to many times, this global index variable will be to big for the array and will be out of bounds for the array.

Both the problem with dereferencing a pointer to an out-of-scope array and the indexing out of bounds leads to undefined behavior. Undefined behavior will, if you're lucky, just lead to the wrong result being printed. If you're unlucky it will cause the program to crash.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • 2
    There is also a third solution, which is to declare a as static. This does create the problem that you can't use this function more than once, or if you do, you must first duplicate the values from the previous function call. – Craig Aug 06 '13 at 07:43
  • 1
    There is one more bug in the code. What about re-initializing the global `n` to `0` in the function? Everytime the array gets populated starting at differnt locations and finally goes out of bound after few function calls.. – Uchia Itachi Aug 06 '13 at 07:52
  • There is fourth solution to use a global array. – Uchia Itachi Aug 06 '13 at 07:54
  • @UchiaItachi Using a global array leads to much the same problems as using a `static` local array. – Some programmer dude Aug 06 '13 at 08:01
  • Yes, I agree. But it was only for this example. :) – Uchia Itachi Aug 06 '13 at 08:02
  • Another bug is that numbers larger than 1023 (10 binary digits) will overrun the array. Also negative numbers will leave negative values in the output, which is probably not intended. – Jason C Aug 06 '13 at 08:24
  • 1
    Oh, and, yet another option is sticking the array in a struct and returning that. It has the benefit of not having to worry about free(). – Jason C Aug 06 '13 at 08:27
3

You are returning a pointer to a locally allocated array. It is allocated on the stack, and goes away when the function returns, leaving your pointer pointing to garbage.

You have a few options. You could pass an array in to fill:

void DecimalToBinary(int result[10],int number){
    while(number!=0){
        result[n++] = number%2;
        number/=2;
    }
    return result;
}

// usage example:
int b[10];
DecimalToBinary(b, 42);

Or you could allocate an array on the heap:

int* DecimalToBinary(int number){
    int *a = (int *)malloc(sizeof(int) * 10);
    while(number!=0){
        a[n++] = number%2;
        number/=2;
    }
    return a;
}

// usage example
int *b = DecimalToBinary(42);
free(b); // when finished with it

Or you could wrap the array in a struct:

typedef struct {
    int b[10];
} result;

result DecimalToBinary(int number){
    result r;
    while(number!=0){
        r.b[n++] = number%2;
        number/=2;
    }
    return r;
}

// usage example
result r = DecimalToBinary(42);

If you do the malloc() option, do not forget to free() the returned data when you're done with it, otherwise it will hang around. This is called a memory leak. In more complex programs, it can lead to serious issues.

Note: By the way, if your number is larger than 1023 (10 binary digits), you'll overrun the array. You may also wish to explicitly stop once you've stored 10 digits, or pass the size of the array in, or compute the required size first and allocate that much space. Also, you will get some odd results if your number is negative, you might want to use number&1 instead of number%2.

Note 2: As noted elsewhere, you should make n local, or at the very least reinitalize it to 0 each time the function is called, otherwise it will just accumulate and eventually you'll go past the end of the array.

Jason C
  • 38,729
  • 14
  • 126
  • 182
  • 1
    Note that in `void DecimalToBinary(int result[10],int number)`, the "10" is going to be ignored and the array is promoted to an array. So in reality, the signature will be `void DecimalToBinary(int *result, int number)`. – DarkDust Aug 06 '13 at 09:16
  • I like to include the size in the declaration for self-documentation. Just personal preference, there's no other real reason for it. – Jason C Aug 06 '13 at 09:31
1

int[10] is not the same as int *; not only is the former created on the stack, it is a different type alltogether. You need to create an actual int * like so:

int *a = malloc (10 * sizeof (int));

Of course, don't forget to free() it after use!

Nerius
  • 910
  • 6
  • 16
0

What you can also do and what is commonly done in C is creating the array where it is called and provide a pointer to that array to the function, this way when the array is on the stack of the function that calls it and not in the function self. We also have to specify the size of the array on to that function, since the function cannot know to how many elements the pointer points to

void DecimalToBinary( int number, int* output, unsigned size ) {
    /*adapt this to your liking*/
    int i;
    for ( i = 0; i < size && number != 0; i++) {
        output[i] = number%2;
        number/2;
    }
}

and in you main function you would call it like this:

int array[10];
DecimalToBinary( 5, array, sizeof(array)/sizeof(array[0]));

now array has the same result as a would have had in your example.

hetepeperfan
  • 4,292
  • 1
  • 29
  • 47
0

The problem in your code lies here..

int * DecimalToBinary(int number){
int a[10];      
while(number!=0){
    a[n++] = number%2;
    number/=2;
}
return a;

}

The array a scope is only till this function. Once this function terminates, the memory allocated for this array will be released, either u need to use dynamic memory allocation or make array a global.

Amit009
  • 51
  • 3
-1

This is the correct program:

#include <stdio.h>
int  n = 0;
int a[10] = {0};
int* DecimalToBinary(int number){
    n = 0;     
    while(number!=0){
        a[n++] = number%2;
        number = number/2;
    }
    return a;
}

int main(){

    int *d1;
    int *d2;
    int i;
    d1 = DecimalToBinary(5);
    for(i = n-1;i>=0;i--)
        printf(" %d",d1[i]);
    printf("\n");
    d2 = DecimalToBinary(10);
    for(i = n-1;i>=0;i--)
        printf(" %d",d2[i]);
    printf("\n");
}
wrapperm
  • 1,266
  • 12
  • 18