Do I need to initiallize(set to 0) memory after calling realloc?
Asked Answered
T

3

7

I need to implement a simple dynamic array of pointers to a typedef'ed pointer.
Using realloc each time it's requested by the user, the array size will grow by sizeof(pointer).
So what I have is this:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef void* node;

void printmem(node* a, int c) {
    int i;
    for (i = 0; i < c; ++i)
    {
        printf("%d\t\t%p\n", i, a[i]);
    }
}

int main(void) {
    node* nodes = NULL;
    int i = 0, count = 20;

    for (i = 0; i < count; ++i)
    {
        nodes = realloc(nodes, sizeof(node));
    }
    printf("Done reallocating\n");
    printmem(nodes, i);
    // free(a);
    return 0;   
}

This gives the following output:

Done reallocating
0       (nil)
1       (nil)
2       (nil)
3       0x20fe1
4       (nil)
5       (nil)
6       (nil)
7       (nil)
8       (nil)
9       (nil)
10      (nil)
11      (nil)
12      (nil)
13      (nil)
14      (nil)
15      (nil)
16      (nil)
17      (nil)
18      (nil)
19      (nil)

I am concerned about the 3rd element, and its content.
That's why I am asking if I should set to 0 the memory after a new realloc.

Edit:
So, as pointed to the standard of C, by H2CO3, the new call to realloc, is:
nodes = realloc(nodes, (i+1)*sizeof(node));
And after that for initiallization, I did this: nodes[i] = NULL
which also worked just fine.

Edit2:
I have this now:

int main(void) {
    node* nodes = NULL;
    int i = 0, count = 20;

    for (i = 0; i < count; ++i)
    {
        nodes = realloc(nodes, (i+1)*sizeof(node));
        nodes[i] = NULL;
        if (i == 1) {
            nodes[i] = &count;
        }
    }
    printf("Done reallocating\n");
    printmem(nodes, i);
    printf("\t*nodes[1] == %d\n", *(int*)nodes[1]);
    printf("\tAddress of count is %p\n", &count);
    // free(a);
    return 0;   
}
Tube answered 11/1, 2014 at 20:2 Comment(8)
realloc() will copy over whatever originally was in the buffer. If the new block is larger than the original one, then the elements at the end (i. e. the ones that were not present in the original array) will be uninitialized.Tripod
@H2CO3: The new block is surely larger than the older, so all previous data is lost?Tube
Naw. Read my comment one more time. Excess elements will be uninitialized, the original content at the beginning of the memory block is preserved.Tripod
Your realloc call isn't doing what you think it is. You're not extending the allocation, you're repeatedly allocating a block of the same size. Which means that your printmem function is going way beyond the memory you've actually allocated.Enswathe
@H2CO3: That was what confused me "will copy over whatever originally was in the buffer", anyhow, thank you for your comment :)Tube
@NigelHarper: But as it says in the manual page "The realloc() function changes the size of the memory block pointed to by ptr to size bytes.", it changes the size by size bytes. How is that wrong?Tube
@Tube Not "by", rather "to". Read the relevant paragraph in the standard: 7.20.3.4.Tripod
@H2CO3: Aaaahh, now I got it! Thank you very much H2CO3!Tube
D
14

Well, it all depends. Do you require that the memory be initialized to 0? If not, then no, you don't need to do anything. Just as is the case with malloc, realloc doesn't perform any initialization. Any memory past the memory that was present in the original block is left uninitialized.

Disconcerted answered 11/1, 2014 at 20:7 Comment(2)
So should I, call memset for that particular new element that is added each time?Tube
Well, again, that all depends on whether or need you need this memory initialized. If so, then yes. However, it is important to realize that C does not guarantee that the null pointer is represented by all zero bits, only that it will compare equal to 0. A subtle but important difference.Disconcerted
B
2

Going by the definition of realloc()

realloc(void *p, size_t size) changes the size of the object pointed to by p to size. The contents will be unchanged up to the minimum of the old and new sizes. If the new size is larger, the new space is uninitialized. (from Kernighan and Ritchie)

You may have to initialize the new space. You can do that when it is decided what kind of data the address pointed to by the void* will hold.

Brighten answered 11/1, 2014 at 20:21 Comment(0)
B
2

Be aware that the null-pointer does not have to be equal to a literal 0 in C. It is merely guaranteed to not be equal to any valid pointer. Furthermore, null-pointers are technically allowed to be different for different pointer types (e.g. function-pointers vs. char-pointers).

Therefore, simply initialising the memory to zero could invoke undefined behaviour.

So initiallizing to NULL, would be correct! That's what I've done! – Chris

No, what you would have to do is cast the null like this: (void*)NULL, and write this to the memory location. But you never actually write to the memory you malloc (via passing NULL to realloc). You're basically just reading uninitialised memory (which is undefined behaviour) in your printf.

Bid answered 11/1, 2014 at 20:41 Comment(4)
So initiallizing to NULL, would be correct! That's what I've done!Tube
Could you please explain the difference between (void*)NULL and NULL? I've used both and ran with valgrind the program and got no errors. Also, why I am not writing to the memory I've allocated? I've posted an update to the main, if you run it you'll see that nodes[1] prints the address of c variable and by printing *(nodes[i]) I get the value of c.Tube
@Chris: If, on some architecture, nullptr!=zero, then the compiler must know to put the appropriate value into memory. It must know that the referenced bit of memory is to be treated as a pointer. If different pointer-types have different nullptr-values, the compiler must also know what type of null-pointer it needs to write to memory.Bid
"Be aware that the null-pointer does not have to be equal to a literal 0 in C." I guess you meant NULL value is not guaranteed to have zero representation. Using 0 literal instead of NULL macro on pointers is fine.Spondee

© 2022 - 2024 — McMap. All rights reserved.