On RHEL6, I'm facing a strange problem with realloc(). At some point in the program, realloc() returns NULL (the old pointer has an address and there's plently of memory available). What's being allocated is 200 structure elements (structure below). For some reason, when I do a realloc() instead, it works, but I then have to assign the old pointer to the new one. Below is a simplified version of my code.
This is perhaps a server tuning issue more than a programming one. What is your opinion?
Thanks.
//hearder file
typedef struct { /* Variable Node Detail Record */
long next;
long mask;
char *value;
// more stuff...
} NODETEST;
extern NODETEST *oldNodes;
extern NODETEST *newNodes;
//program
#define MAXSIZE 200
// do some stuff with oldNodes....
int alloc_nodes (void)
{
// Allocate or grow the table
oldNodes = (NODETEST *) malloc(MAXSIZE * sizeof(NODETEST));
if( oldNodes == NULL ) {
//handle exception...
exit(1);
}
//oldNodes = (NODETEST *) realloc(oldNodes,MAXSIZE * sizeof(NODETEST)); // *** FAILS
newNodes = (NODETEST *) realloc(oldNodes,MAXSIZE * sizeof(NODETEST)); // *** WORKS
if( newNodes == NULL ){
printf("errno=%d\n", errno );
}else{
oldNodes = newNodes; }
}
Your first call malloc
with a size S and then realloc
with the same size S. This is wrong: you have to pass to realloc
the new wanted size (independently of the current size - it is not an increment). Here, there is a big chance realloc
returns exactly the same pointer it received. BTW it is not clear why you want to do with a malloc
immediately followed by a realloc
. Gives us more detail.
If you want a dynamic table whose size auto-adjusts, you need to allocate an initial size storing its size in a variable (e.g. alloc_size
) and keep the current number of occupied elements in another variable (e.g. n_elem
) . When you add an element you increment this number. When the table is full reallocate it. Here is a sketch
NODETEST *newNodes = NULL;
int allocated_elem = 0;
int n_elem = 0;
#define ALLOC_INCR 200
then at each addition:
if (n_elem >= alloc_size) { // the first time realloc is as malloc since nodes == NULL
alloc_size += ALLOC_INCR;
nodes = (NODETEST *) realloc(nodes, alloc_size * sizeof(NODETEST));
if (nodes == NULL) {
//handle exception...
exit(1);
}
}
// add your element at nodes[n_elem]
n_elem++;
Recall that realloc acts like malloc when the received pointer is NULL
(case of the first call). Thus it allocates the initial table. Subsequent calls reallocate it by adjusting the size with a constant increment (here 200). Some other schemes are possible for the enlargement of the table, for instance you can multiply the size by a factor (e.g. 2) starting from 32:
if (n_elem >= alloc_size) { // the first time realloc is as malloc since nodes == NULL
alloc_size = (alloc_size == 0) ? 32 : alloc_size * 2;
Regarind the FAIL
and WORKS
comments: it is clear that if you assign oldNodes
(in the FAIL
code) then newNodes
is not assigned and keeps its initial value which is zero (NULL
) since it is declared as a global variable and not initialized (well I suppose, it is extern
here). Thus the test if (newNodes == NULL)
will probably fail.