Double pointer null check in c

483 Views Asked by At

How to check if a double pointer is NULL in the C language ?

I pass a double pointer how parameter of a function.

I need to check twice, like so ???

typedef struct no_t no_t;

struct no_t
{
    no_t *prev;
    no_t *next;
    void *obj;
};

int32_t dynll_free_node_and_object(no_t **node)
{
    if (node == NULL)
        return -1;
    
    if (*node == NULL)
        return -2; 

    free((*node)->obj);
    (*node)->obj = NULL;
    
    (*node)->prev = NULL;
    (*node)->next = NULL;

    free(*node);  
    *node = NULL;
    
    return 0; 
}
3

There are 3 best solutions below

0
Harith On
if( node == NULL )
    return -1;
    
if( *node == NULL )
    return -2;

That is one way to do it. Code risks invoking undefined behaviour if only *node was checked (node could potentially be NULL), or if it was checked first (for the aforementioned reason).

If the different return values only serves noise, consider returning -1 if either is NULL:

if (!node || !(*node)) {
    return -1;
}

You may instead want to abort() the program:

/* assert() would be disabled in release build. */
abort ();

Or perhaps simulate free(NULL) by allowing a NULL pointer. It will be a NOP.

Note that setting these pointers to NULL like so:

(*node)->obj = NULL;
(*node)->prev = NULL;
(*node)->next = NULL;

is pointless because the subsequent assignment of NULL to *node invalidates it. *node no longer points to its original location, so the freed memory can not be accessed through it. (It's not your problem if the caller saved a copy of the original pointer and tried to access memory after it was freed). — @n.m.

2
Lærne On

You can also use the fact that || will short-circuit its right-hand side if it can. I.e if the left hand-size evaluates to 1 (or any non-zero value), it will not run the expression on its right-hand side.

if(node == NULL || *node == NULL)
  return -1;

That makes you use the same return code on failure though.

0
chqrlie On

Checking both node and *node is fine, but the function could be documented as only accepting a non null address and passing the address of a null pointer might not be an error. For example free(NULL) is perfectly fine.

Also note that setting the fields to NULL is optional as you free the structure memory anyway and reset *node to NULL so the calling code would have to dereference a copy of the original pointer to attempt to read the freed structure and this would have undefined behavior anyway.

Here is a simplified version:

#include <assert.h>
#include <stdlib.h>

typedef struct no_t {
    no_t *prev;
    no_t *next;
    void *obj;
} no_t;

void dynll_free_node_and_object(no_t **node) {
    assert(node);
    
    if (*node) {
        free((*node)->obj);
        free(*node);
        *node = NULL;
    }
}