C does not generally permit arrays to be declared with variable sizes. C also doesn’t let local variables outlive the function they are declared in. Both features can be awkward if you want to build data structures at run time that have unpredictable (perhaps even changing) sizes and that are intended to persist longer than the functions that create them. To build such structures, the standard C library provides themallocroutine, which asks the operating system for a block of space of a given size (in bytes). With a bit of pushing and shoving, this can be used to obtain a block of space that for all practical purposes acts just like an array.
To use malloc, you must includestdlib.hat the top of your program. The declaration formallocis
void *malloc(size_t);
wheresize_tis an integer type (oftenunsigned long). Callingmalloc with an argument ofnallocates and returns a pointer to the start of a block ofn bytes if possible. If the system can’t give you the space you asked for (maybe you asked for more space than it has),mallocreturns a null pointer. It is good practice to test the return value of mallocwhenever you call it.
Because the return type of mallocisvoid *, its return value can be assigned to any variable with a pointer type. Computing the size of the block you need is your responsibility—and you will be punished for any mistakes with difficult- to-diagnose buffer overrun errors—but this task is made slightly easier by the built-insizeof operator that allows you to compute the size in bytes of any particular data type. A typical call tomalloc might thus look something like this:
#include <stdlib.h>
/* allocate and return a new integer array with n elements */ /* calls abort() if there isn't enough space */
int *
makeIntArray(int n) {
int *a;
a = malloc(sizeof(int) * n);
return a; }
examples/pointers/makeIntArray.c
If you don’t want to do the multiplication yourself, or if you want to guarantee that the allocated data is initialized to zero, you can use calloc instead of malloc. The calloc function is also declared in stdlib.h and takes two arguments: the number of things to allocated, and the size of each thing. Here’s a version ofmakeIntArray that usescalloc. Aside from zeroing out the data, it is equivalent to themallocversion.
#include <stdlib.h>
/* allocate and return a new integer array with n elements */ /* initializes array to zero */
/* calls abort() if there isn't enough space */
int *
makeIntArray(int n) {
int *a;
a = calloc(n, sizeof(int));
if(a == 0) abort(); /* die on failure */
return a; }
examples/pointers/calloc.c
When you are done with a region allocated using malloc’d or calloc, you should return the space to the system using thefree routine, also defined in stdlib.h. If you don’t do this, your program will quickly run out of space. The free routine takes avoid * as its argument and returns nothing. It is good practice to write a matchingdestructorthat de-allocates an object for each constructor(like makeIntArray) that makes one.
void
destroyIntArray(int *a) {
free(a); }
It is a serious error to do anything at all with a block after it has beenfreed. This is not necessarily becausefreemodifies the contents of the block (although it might), but because when you free a block you are granting the storage allocator permission to hand the same block out in response to a future call tomalloc, and you don’t want to step on whatever other part of your program is now trying
to use that space.
It is also possible to grow or shrink a previously allocated block. This is done using thereallocfunction, which is declared as
void *realloc(void *oldBlock, size_t newSize);
Thereallocfunction returns a pointer to the resized block. It may or may not allocate a new block. If there is room, it may leave the old block in place and return its argument. But it may allocate a new block and copy the contents of the old block, so you should assume that the old pointer has beenfreed. Here’s a typical use ofreallocto build an array that grows as large as it needs to be:
/* read numbers from stdin until there aren't any more */ /* returns an array of all numbers read, or null on error */ /* returns the count of numbers read in *count */
int *
readNumbers(int *count /* RETVAL */) {
int mycount; /* number of numbers read */
int size; /* size of block allocated so far */
int *a; /* block */
int n; /* number read */
mycount = 0; size = 1;
a = malloc(sizeof(int) * size); /* allocating zero bytes is tricky */ if(a == 0) return 0;
while(scanf("%d", &n) == 1) {
/* is there room? */ while(mycount >= size) {
/* double the size to avoid calling realloc for every number read */
size *= 2;
a = realloc(a, sizeof(int) * size);
if(a == 0) return 0; }
/* put the new number in */
a[mycount++] = n; }
/* now trim off any excess space */
a = realloc(a, sizeof(int) * mycount);
/* save out mycount */
*count = mycount;
return a; }
examples/pointers/readNumbers.c
Because errors involvingmallocand its friends can be very difficult to spot, it is recommended to test any program that usesmallocusingvalgrind.