简体   繁体   中英

Why does realloc() fail where malloc() succeds in C?

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 (eg alloc_size ) and keep the current number of occupied elements in another variable (eg 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 (eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM