2

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 );
    }
}
Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
PluffTed
  • 53
  • 5

1 Answers1

1

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).

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
  • Your response states **And use a temporary pointer to avoid the loss of the original pointer in that case....**. It is my understanding that `realloc` will preserve the memory block and extend per the request. [Dynamic Memory Allocation in C using malloc(), calloc(), free() and realloc()](https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/). Can you please elaborate on your thoughts? – Mahendra Gunawardena Dec 30 '21 at 13:56
  • @MahendraGunawardena unfortunately your understanding is wrong. As you can imagine, there are several ways to implement heap memory, and none of them can afford to reserve an undefined number of bytes after each heap area returned by `malloc` just in case a `realloc` will be required. :) So, after the area pointed by the original pointer there will tipically be another area assigned by malloc to another pointer. [continues] – Roberto Caboni Dec 30 '21 at 15:38
  • 1
    @MahendraGunawardena What is guaranteed, as explained in the [manual](https://linux.die.net/man/3/realloc), is that _"The contents will be unchanged in the range from the start of the region up to the minimum of the old and new sizes."_ I modified my answer adding a note with this explaination, and improving the reccomendation you qouted explaining what happens when `realloc` fails (NULL is returned). – Roberto Caboni Dec 30 '21 at 15:41
  • Thank you for the response and elaboration. So the explanation for `realloc` in the attached link in my previous comment is misleading. – Mahendra Gunawardena Dec 30 '21 at 15:49
  • @MahendraGunawardena actually it is not: it states that "realloc can be used to dynamically re-allocate memory. re-allocation of memory **maintains the already present value** and new blocks will be initialized with the default garbage value."_ So it confirms that **values* (aka **contents**) are preserved. It doesn't mention that also the memory locations data is stored in is preserved. – Roberto Caboni Dec 30 '21 at 16:03
  • @RobertoCaboni Interesting discussion. So if the heap is continuously growing through dynamic memory allocation, in a memory constrained system such as an embedded system, `realloc` will require double the memory footprint from the current memory allocation. So it looks like using a `malloc` and a `linked list` approach might be better than `realloc` for a memory constrained system. – 706Astor Dec 30 '21 at 20:27