When writing functions in C, what considerations govern the way in which results are returned from the function? My question arises from reading the following code, which creates a node in a doubly-linked list, and which comes from this book:
typedef struct DLLIST
{
uint16 tag; /* This node's object type tag */
struct DLLIST *next;
struct DLLIST *previous;
void *object;
uint32 size; /* This node's object size */
} DLLIST;
DLLIST *dlCreate(uint16 tag, void *object, uint32 size)
{
DLLIST *newNode;
newNode = malloc(sizeof(*newNode));
if (newNode != NULL)
{
newNode->previous = NULL;
newNode->next = NULL;
newNode->tag = tag;
newNode->size = size;
newNode->object = malloc(size);
if (newNode->object != NULL)
{
memcpy(newNode->object, object, size);
}
else
{
free(newNode);
newNode = NULL;
}
}
return newNode;
}
Indeed, there are many aspects of this function that as a beginner I find perplexing:
- Why is the DLLIST pointer returned this way, rather than being passed as a reference pointer and modified? If you did this, you could free up the return value for use as a status byte that reported function success/failure.
- Why is the second argument not tested to ensure that the pointer is not NULL? Surely passing a NULL pointer to memcpy would be a very bad thing?
Furthermore, is it common practice to force ALL functions within a module to use the same calling convention? For example, should all functions within the doubly-linked list module from which the function above is taken conform to status byte = function(argument list)? In addition, is it common practice to validate ALL function arguments whose value may be incorrect? For example, check all pointer values to ensure they are not null?