Tomasz Kramkowski

malloc, realloc and sizeof

I spend a lot of time in ##c hoping to provide useful information to people wishing to learn and understand C and almost every day I see malloc and realloc code which appears to be straight from a horror movie. I've had to say what I say in this post repeatedly to many people so I've decided that it's time to write it once and simply give people a link every time I wish to explain why such code is incorrect.

The code I'm describing is usually a combination of some or all of this:

struct foo *bar;

bar = (struct foo *)malloc(sizeof(struct foo) * 10);

bar = (struct foo *)realloc(bar, sizeof(struct foo) * 20);

There are multiple issues with this:

The easy solution is simply:

struct foo *bar, *tmpbar;

bar = malloc(sizeof *bar * 10);

tmpbar = realloc(bar, sizeof *tmpbar * 20);

if (!tmpbar) {
	free(bar);
	/* error handling */
} else {
	bar = tmpbar;
}

This solves all of the outlined problems.


Here's the answers to two common questions:

Q: The compiler has always complained (warned) when I tried to assign a pointer to one type to a pointer to another type. Would this not be the case here?

A: The C standard states (C11/C99 §6.3.2.3 and C11/C99 §6.5.16.1) roughly that a pointer to void can be assigned to a pointer to any type, and vice versa, freely without issuing a warning. This in turn means that the return value of malloc (and any other function returning void *) will be converted without warning to the desired type without needing a cast.

Q: What's the deal with sizeof *bar? Don't functions need brackets?

A: The sizeof operator can be given an expression as an operand as well as the parenthesized name of a type. This means we can do sizeof *bar. Also, since sizeof is an operator and not a function, it doesn't require parentheses when its operand is an expression, the C standard does however require that for types, the type name has to be parenthesized. In the end, it's a style choice whether the parentheses are always there or not, but personally I think leaving them out is more consistent. (NB: The first example uses sizeof as such: sizeof(type), personally I prefer leaving a space between sizeof and (type) as I would with most other operators.)