简体   繁体   中英

Program doesn't output anything using a dynamic array

I just started with C and I am trying to create a program which takes a number and converts it to binary using this method (from indepth.dev ):

To convert integer to binary, start with the integer in question and divide it by 2 keeping notice of the quotient and the remainder. Continue dividing the quotient by 2 until you get a quotient of zero. Then just write out the remainders in the reverse order. (...) Now, we simply need to write out the remainder in the reverse order —1100. So, 12 in decimal system is represented as 1100 in binary.

I am trying to make the array dynamic in size. Coming from Python this is a bit confusing, because in Python you can just append to a list.

Here is my code so far:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

int main() 
{
    int *ptr, n, i;
    ptr = (int*)malloc(1 * sizeof(int));
    printf("Enter a number to convert: ");
    scanf("%d", &n);
    for (i = 0; n>0; i++)
    {   
        ptr = realloc(ptr, i * sizeof(int));
        ptr[i] = n % 2;
        n = n/2;

    }

    for(i=i-1; i>= 0; i--)
    {
        printf("%d", ptr[i]);
    }
    free(ptr);
    return 0;
}

When I run the program and enter a number it doesn't output anything. If I do the same with a fixed array size it works. Why is this happening?

The problem lies in these few lines:

for (i = 0; n>0; i++)
{   
    ptr = realloc(ptr, i * sizeof(int));
    ptr[i] = n % 2;
    n = n/2;
}

You are reallocating an array capable of holding i integers each time, however you end up writing at index i . An array holding i integers has indexes from 0 to i - 1 , and you are therefore writing past the end of the array. This results in undefined behavior .

The easiest fix for this is to just start with i = 1 and write to ptr[i - 1] :

for (i = 1; n > 0; i++)
{   
    ptr = realloc(ptr, i * sizeof(int));
    ptr[i - 1] = n % 2;
    n = n/2;
}

A simpler approach would be to use a fixed size array. You already know that an int is 8*sizeof(int) bits long, so that's the maximum you'll need. Also, you probably don't need to work with signed integers since those can cause problems with negative values (therefore you can use unsigned ).

EDIT: I am saying 8 * sizeof(int) because the sizeof operator returns the size of the type (in this case int ) in bytes. A byte is 8 bits, so I multiply that by 8 to get the size in bits. I said 8 here, but using CHAR_BIT (from limits.h ) would be better, because a "byte" in C could be expressed using more than 8 bits and in that case CHAR_BIT holds the right number of bits per byte. I'm not aware of any C implementation that has a value different than 8 for CHAR_BIT , but it's nonetheless the correct way to go. I updated the code below to use CHAR_BIT instead of 8 .

#include <stdio.h>
#include <limits.h>
#define N_BITS CHAR_BIT * sizeof(unsigned)

int main(void) {
    unsigned digits[N_BITS] = {0}; // Start with an array filled with zeroes.
    unsigned n;
    int i;

    printf("Enter a number to convert: ");
    scanf("%u", &n);

    // Calculate binary digits.
    for (i = 0; n > 0; i++) {
        digits[i] = n % 2;
        n /= 2;
    }

    // Skip leading zeroes.
    while (digits[i] == 0)
        i--;

    // Print binary digits in reverse order.
    for(; i >= 0; i--)
        printf("%u", digits[i]);

    // Final newline.
    putchar('\n');

    return 0;
}

Bonus:

#include <stdio.h>

int main(void) {
    int i = 8 * sizeof(unsigned);
    unsigned n;

    printf("Enter a number to convert: ");
    scanf("%u", &n);

    while (i--)
        putchar('0' + ((n >> i) & 1));
    putchar('\n');

    return 0;
}

You allocated not enough memory. If sizeof( int ) is equal to 4 then the number of binary digits can be equal to 32 ( sizeof( int ) * CHAR_BIT ).

And there is no need to use realloc.

Moreover this statement

ptr = realloc(ptr, i * sizeof(int));

allocates memory of zero size when i in the loop is equal to 0. You may not write to such a memory.

Also you should use an object of the type unsigned int.

Here is a demonstrative program.

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main(void) 
{
    unsigned int Base = 2;

    int *ptr = malloc( CHAR_BIT * sizeof( unsigned int ) );

    printf( "Enter a number to convert: " );

    unsigned int x = 0;

    scanf( "%u", &x );

    size_t n = 0;

    do
    {
        ptr[n++] = x % Base; 
    } while ( x /= Base );

    while ( n-- )
    {
        printf( "%u", ptr[n] );
    }
    putchar( '\n' );

    free( ptr );

    return 0;
}

Its output might look like

Enter a number to convert: 12
1100

If you want to use realloc then the code can look like

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

int main(void) 
{
    unsigned int Base = 2;

    int *ptr = NULL;

    printf( "Enter a number to convert: " );

    unsigned int x = 0;

    scanf( "%u", &x );

    size_t n = 0;

    do
    {
        ptr = realloc( ptr, ( n + 1 ) * sizeof( unsigned int ) );
        ptr[n++] = x % Base; 
    } while ( x /= Base );

    while ( n-- )
    {
        printf( "%u", ptr[n] );
    }
    putchar( '\n' );

    free( ptr );

    return 0;
}

In general such a call

ptr = realloc( ptr, ( n + 1 ) * sizeof( unsigned int ) );

is unsafe because the function can return NULL. So in general you should use an intermediate variable like

unsigned int *tmp = realloc( ptr, ( n + 1 ) * sizeof( unsigned int ) );
if ( tmp ) ptr = tmp;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM