csegmentation-faultmallocreallocgetc

Inserting into a dynamic character array while using realloc()


I am very much wanting to catch up on my C programming skills, so I have started my own self-training program, attempting to reading files and inserting their contents into different data structures.

Here, I am wanting to use specifically a dynamically-allocated pointer array. I have already used getc() successfully in another similar program, but instead through the use of a static array, so I would very much like to continue using the getc() function here.

So in this new implementation, here, I am just trying to insert all characters from an input file into an array, which I allocated using malloc(). After one character is read at a time, I am trying to resize this pointer array by the size of one character each time so that there is room for the next character on the next iteration. Then, afterwards, iterate [character by character] through the new pointer array and simply print out all the contents.

However, I am receiving segmentation faults, so maybe I am going about this a little wrong? I would appreciate very much any feedback.

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

void main( int argc, char *argv[] )
{

    FILE *filePointer;
    int c, i;
    char *input_arrayPointer;
    input_arrayPointer = ( char* ) calloc ( 1, sizeof( char ) );
    printf("%p\n", input_arrayPointer);
    int filled_elements = 0;
    filePointer = fopen( argv[1], "r" );

    if ( argc > 2 )
    {
        printf( "\nIncorrect usage, please say...\nRunProgram *filename*\n\n" );
        exit( 1 );
    }

    if ( filePointer != NULL )
    {   
        while ( ( c = getc( filePointer ) ) != EOF )
        {
            // filled_elements, to start, is 0

            *( input_arrayPointer + filled_elements ) = c;
            filled_elements++;
            input_arrayPointer = ( char* ) realloc ( input_arrayPointer, (filled_elements * sizeof( char ) ) );
        }
    }

    fclose( filePointer );

    for ( i = 0; i < filled_elements; i++, input_arrayPointer++ )
    {
        printf("%c", *( input_arrayPointer + filled_elements );
    }
}

Solution

  • In

    while ( ( c = getc( filePointer ) ) != EOF )
    {
        // filled_elements, to start, is 0
    
        *( input_arrayPointer + filled_elements ) = c;
        filled_elements++;
        input_arrayPointer = ( char* ) realloc ( input_arrayPointer, (filled_elements * sizeof( char ) ) );
    }
    

    What happens at the very first iteration?

    1. input_arrayPointer is one byte big
    2. filled_elements is 0
    3. The first byte of input_arrayPointer is written
    4. filled_elements is incremented
    5. realloc is called for filled_elements bytes... that is 1!!! No array size increment!
    6. The second character is written to an illegal address (outside dynamically allocated area)

    You just need to allocate one byte more

    input_arrayPointer = ( char* ) realloc ( input_arrayPointer, ((filled_elements+1) * sizeof( char ) ) );
    

    Better: always check realloc return value. And use a temporary pointer to avoid the loss of the original pointer in case it fails.
    When does realloc fail? When it doesn't succeed in allocating the requested size. In that case, as described in man page, NULL will be returned and assigned to input_arrayPointer. That's not what you want.
    Something like that will avoid the issue:

    char *temp = realloc ( input_arrayPointer, ((filled_elements+1) * sizeof( char ) ) );
    if (temp != NULL)
    {
        input_arrayPointer = temp;
    }
    

    Note: realloc does not guarantee to extend the original pointer, as it has to find a contiguous memory range wide enough to contain the requested size. Instead, it finds the new memory area and copies there the original contents of the pointer (all of it, if newSize > oldSize; newSize bytes otherwise).