Skip to content
Physics and Astronomy
Home Our Teaching Resources C programming PHY3134 alloc.html
Back to top

Computational Physics
Allocating space

malloc

You have already met the malloc function:
#include <stdio.h>
#include <stdlib.h>

#define N 100
int
main() {
  float *p;

  p = malloc(N * sizeof *p);
  if (p == NULL) {
    fprintf(stderr, "Out of memory!\n");
    exit(-1);
  }
  p[0] = p[1] = 3.14159;
  /* Use p for something */
  return 0;
}
p above is called a pointer, a concept introduced in the previous module. Once you have allocated some memory for it you can use a pointer just like an array.

The sizeof operator

For any pointer p the expression sizeof *p returns the number of bytes needed for whatever p points to. It's the ideal argument to malloc! There's also a version sizeof(float) which is less useful.

NULL

AS with fopen, NULL is used to indicate that malloc ran out of memory. You must always check that malloc did not return NULL. The exit() function above does pretty much what it says. By convention, successful programs exit with zero. NULL and exit()are declared in <stdio.h> and <stdlib.h> respectively.

You are welcome to check the result of malloc every time you call it. You are equally welcome to define a function like:

void *xmalloc(size_t n) {
  void *p = malloc(n);
  if (p == NULL) {
    fprintf(stderr, "Out of memory!\n");
    exit(-1);
  }
  return p;
}
and to call xmalloc instead of malloc. I know which I prefer to do!

Arrays of pointers

These work in the obvious way:
#define N 100
#define M 4
int
main() {
  float *p[M];
  int i;

  for (i = 0; i < M; ++i)
    p[i] = xmalloc(N * sizeof *p[i]);

  p[0][1] = 3.14159;
  /* Use p for something */
  return 0;
}

Dynamically allocated '2-D arrays'

Of course, often we won't know how many pointers we will need so we can dynamically allocate them too. The following function allocates memory that can then be used like a two dimensional array (but see note below).
int **
new2dint(int m, int n) {
  int **p;
  int i;

  p = xmalloc(m * sizeof *p);
  for (i = 0; i < m; ++i)
    p[i] = xmalloc(n * sizeof *p[i]);
  return p;
}

int
main() {
  int **p = NULL;
  int n;

  do {
    printf("Size of array (>0)?\n");
    scanf("%i", &n);
  } while (n <= 0);

  p = new2dint(n, n);
  p[0][0] = 17;
  p[n-1][0] = 13;
  p[n-1][n-1] = 10;

  return(0);
}

Differences from true multi-dimensional arrays

Executive summary: the things above may look like ordinary two-dimensional arrays but they're not

At first sight p above looks just like a "real" array, in that their elements are accessed using the same source-level notation:

  int array[M][N];
  int **p = NULL;

  p = new2dint(M, N);

  p[1][7] = 17;
  array[1][7] = 17;
However, p and array are different things. p is a pointer to M pointers to N ints. By contrast, array points to a single block of M*N ints.

They are dereferenced as follows:


p[i][j] => *( *(p+i) + j)  
Double deference: deference (p+i), add j and dereference the result.
array[i][j] => *(array + (N*i + j))
Single deference: add N*i+j to array and dereference that.

This is why for functions which have arguments which are multidimensional arrays you mut tell the function the size of the array (which the left-most size being optional):

int oldstylefun(float array[][N]);
int newstylefun(int n, float array[][n]);
int three_d_fun(int m, int n, float array[][m][n]);

Allocating structures

This works just you would expect:
struct thingy *p;
p = xmalloc(sizeof *p);
In practice however it's a very good idea to define a function whose job is to allocate the space for a structure and do any initialisation:
#include <stdlib.h>

typedef struct wotsit {
  float val;
  char *str;
  int length;
} Wotsit;


Wotsit *newwotsit(int len) {
  Wotsit *w = xmalloc(sizeof *w);

  w->length = len;
  w->val = 0;
  w->str = xmalloc(w->length);
  return w;
}

int main() {
  Wotsit *william = newwotsit(100);
  /* Blah, blah, blah */
}

In practice structures are nearly always dynamically allocated, seldom statically.

Freeing memory

When you've finished with some memory you should get rid of it so it can be reused. If you fail to do this your program will gradually use more and more memory until the computer runs out. (When your program finishes it will automatically free any memory it was still using.)

The absolute rule is that you can't use memory after you've freed it and you can free it only once. To reuse the above example we might define a function freewotsit():

void freewotsit(Wotsit *w) {
  free(w->str);
  free(w);
}
The above version is correct. Had we written:
  free(w);
  free(w->str);
It would have been very, very wrong.
                                                                                                                                                                                                                                                                       

Validate   Link-check © Copyright & disclaimer Privacy & cookies Share
Back to top