Search code examples
carraysmemorymemory-managementrealloc

C. The difference between realloc in double array and char array


I have to dynamically increase a length of double array. I know, how to do it with char array, so I tried this:

int main() {
    char * tmp = NULL;
    for (int i = 1; i <= 4; i++) {
        tmp = realloc(tmp, i * sizeof(char));
        tmp[i] = 'i';
    }
    puts("char OK");
    double * tmp1 = NULL;
    for (int i = 1; i <= 4; i++) {
        tmp1 = realloc(tmp1, i * sizeof(double));
        tmp1[i] = 0;
    }
    return 0;
}

The first array works fine. But the second one crushes with message realloc(): invalid next size.

These are my 2 questions:

  1. Why this way doesn't work in a double array?
  2. How to dynamically increase the size of array of doubles?

UPD: removed a typo


Solution

  • TL;DR: Both the snippets are wrong, the first one appears to work because of undefined behavior.

    To elaborate, the problem is with your indexing logic. C uses a 0-based indexing. So, inside the loop which is staring the iteration from value of i as 1, by using

     tmp[i] = .......
    

    you're trying to access invalid memory, at this point, only access up to tmp[i-1] is valid.

    You need to use tmp1[i-1] = 0;, and likewise.


    That said,

    1. Always check for the success of the memory allocator functions before using the returned pointers.
    2. Never use the form

        pointer = realloc (pointer, ......)
      

      because, in case realloc call fails, you'll end up losing the original pointer, too.

      Quoting C11, chapter §7.22.3.5

      The realloc function returns a pointer to the new object (which may have the same value as a pointer to the old object), or a null pointer if the new object could not be allocated.

      and

      [....] If memory for the new object cannot be allocated, the old object is not deallocated and its value is unchanged.

      • Always use a temporary pointer variable to store the return value of realloc(),
      • check for the success of the call [not-null return value] and
      • then assign it back to the original variable, if needed.