Search code examples
cdynamic-memory-allocationreallocfunction-definitionnull-pointer

Getting address boundary error when working with pointers in C


The following code gives me a terminated by signal SIGSEGV (Address boundary error):

void rec(int x, int *arr, int *size) {
  if (x < 0) {
      rec(-x, arr, size);
      return;
  }
  arr = realloc(arr, sizeof(int) * ++(*size));
  *(arr + (*size) - 1) = x % 10;
  if (x % 10 != x)
      rec(x / 10, arr, size);
}

int main() {
    int *arr = malloc(sizeof(int));
    int *size = malloc(sizeof(int));
    *size = 0;
    rec(20, arr, 0);
}

I already figured our that the arr counter in the main method won't hold the desired result, but I still can't understand why I'm getting an error.


Solution

  • For starters these memory allocations

    int *arr = malloc(sizeof(int));
    int *size = malloc(sizeof(int));
    

    does not make a sense. They are redundant.

    You could just write

    int *arr = NULL;
    size_t size = 0;
    

    Secondly the variable size is declared but not used because instead of the variable you passed the integer constant 0

    rec(20, arr, 0);
    

    So within the function rec

    void rec(int x, int *arr, int *size);
    

    the pointer size was initializer by the null pointer constant 0. That is size is a null pointer within the function and using a null pointer to access memory results in undefined behavior.

    Also you should pass the pointer to the function by reference. Otherwise passing it to the function does not make a great sense because the pointer in main will not be changed.

    The code in main could look like

    int *arr = NULL;
    size_t size = 0;
    
    rec( 20, &arr, &size );
    

    Pay attention to that you should free all the allocated memory when it will not be used any more.

    Correspondingly the function should be declared like

    void rec(int x, int **arr, size_t *size);
    

    Use the type size_t instead of the type int because this unsigned integer type is the type of the second argument of the function realloc.

    In general to get the result of realloc you should use an intermediate variable because the function can return a null pointer and the current pointer will be lost.

    Also pay attention to that the call of the function is unsafe and can result in an infinite recursion due to this if statement

      if (x < 0) {
          rec(-x, arr, size);
          return;
      }
    

    when the user passes to the function the value of x equal to INT_MIN.

    Consider the following demonstrative program.

    #include <stdio.h>
    #include <limits.h>
    
    int main(void) 
    {
        int x = INT_MIN;
        
        printf( "x = %d\n", x );
        printf( "-x = %d\n", -x );
    
        return 0;
    }
    

    Its output might look like

    x = -2147483648
    -x = -2147483648
    

    As you can see negating the value of the variable x you get the same negative value. So maybe it is better to declare the first function parameter as having the type unsigned int.

    Your function can look for example the following way as it is shown in the demonstrative program below.

    #include <stdio.h>
    #include <stdlib.h>
    
    int rec( unsigned int x, unsigned int **arr, size_t *size ) 
    {
        const unsigned int Base = 10;
        
        unsigned int *tmp = realloc( *arr, sizeof( int ) * ++*size );
        int success = tmp != NULL;
        
        if ( success )
        {
            *arr = tmp; 
            *( *arr + *size - 1 ) = x % Base;
            if ( x % Base != x )
            {
                success = rec( x / Base, arr, size );
            }
        }
        
        return success;
    }
    
    int main(void) 
    {
        unsigned int *arr = NULL;
        size_t size = 0;
        
        rec( 123456789, &arr, &size );
        
        for ( size_t i = 0; i < size; i++ )
        {
            printf( "%u", *( arr + i ) );
        }
        
        putchar( '\n');
        
        free( arr );
        
        return 0;
    }
    

    The program output is

    987654321