Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Consider the following example:

Code Block
bgColor#ffcccc
langc
#include <stdlib.h>

typedef struct gadget gadget;
struct gadget {
  int i;
  double d;
};

typedef struct widget widget;
struct widget {
  char c[10];
  int i;
  double d;
};

widget *p;

/* ... */

p = malloc(sizeof(gadget)); /* imminent problem */
if (p != NULL) {
  p->i = 0;               /* undefined behavior */
  p->d = 0.0;             /* undefined behavior */
}

An implementation may add padding to a gadget or widget so that sizeof(gadget) equals sizeof(widget), but this is highly unlikely. More likely, sizeof(gadget) is less than sizeof(widget). In that case

Code Block
bgColor#FFcccc
langc
p = malloc(sizeof(gadget)); /* imminent problem */

...

In this code example, malloc() allocates space for a gadget and the cast immediately converts the returned pointer to a gadget *:

Code Block
bgColor#ffcccc
langc
widget *p;

/* ... */

p = (gadget *)malloc(sizeof(gadget)); /* invalid assignment */

...

This compliant solution repeats the same type in the sizeof expression and the pointer cast.

Code Block
bgColor#ccccff
langc
widget *p;

/* ... */

p = (widget *)malloc(sizeof(widget));

...

Repeating the same type in the sizeof expression and the pointer cast is easy to do but still invites errors. Packaging the repetition in a macro, such as

Code Block
bgColor#ccccff
langc
#define MALLOC(type) ((type *)malloc(sizeof(type)))

further reduces the possibility of error.

Code Block
bgColor#ccccff
langc
widget *p;

/* ... */

p = MALLOC(widget);     /* OK */
if (p != NULL) {
  p->i = 0;           /* OK */
  p->d = 0.0;         /* OK */
}

...

When allocating an array with N elements of type T, the appropriate type in the cast expression is still T *, but the argument to malloc() should be of the form N * sizeof(T). Again, packaging this form as a macro, such as

Code Block
bgColor#ccccff
langc
#define MALLOC_ARRAY(number, type) \
    ((type *)malloc((number) * sizeof(type)))

reduces the chance of error in an allocation expression.

Code Block
bgColor#ccccff
langc
enum { N = 16 };
widget *p;

/* ... */

p = MALLOC_ARRAY(N, widget);    /* OK */

A small collection of macros can provide secure implementations for common uses for the standard memory allocation functions. The omission of a REALLOC() macro is intentional. (See recommendation MEM08-C. Use realloc() only to resize dynamically allocated arrays.)

Code Block
bgColor#ccccff
langc
/* allocates a single object using malloc(). */
#define MALLOC(type) ((type *)malloc(sizeof(type)))

/* allocates an array of objects using malloc(). */
#define MALLOC_ARRAY(number, type) \
    ((type *)malloc((number) * sizeof(type)))

/* allocates a single object with a flexible
 * array member using malloc(). */
#define MALLOC_FLEX(stype, number, etype) \
    ((stype *)malloc(sizeof(stype) \
    + (number) * sizeof(etype)))

/* allocates an array of objects using calloc(). */
#define CALLOC(number, type) \
    ((type *)calloc(number, sizeof(type)))

/* reallocates an array of objects using realloc(). */
#define REALLOC_ARRAY(pointer, number, type) \
    ((type *)realloc(pointer, (number) * sizeof(type)))

/* reallocates a single object with a flexible
 * array member using realloc(). */
#define REALLOC_FLEX(pointer, stype, number, etype) \
    ((stype *)realloc(pointer, sizeof(stype) \
    + (number) * sizeof(etype)))

The following is an example:

Code Block
bgColor#ccccff
langc
enum month { Jan, Feb, /* ... */ };
typedef enum month month;

typedef struct date date;
struct date {
  unsigned char dd;
  month mm;
  unsigned yy;
};

typedef struct string string;
struct string {
  size_t length;
  char text[];
};

date *d, *week, *fortnight;
string *name;

d = MALLOC(date);
week = MALLOC_ARRAY(7, date);
name = MALLOC_FLEX(string, 16, char);
fortnight = CALLOC(14, date);

...