Tutorial Thirteen – allocating memory in C

This is the thirteenth tutorial in the series Online C Tutorials for beginners and is about allocating memory. These tutorials are single page bite size tutorials which can usually be run on either codepad.org or ideone.com.

You can get by with many C programs never needing to allocate dynamic memory, but there comes a time when you need to. Anything involving lots of text strings, or linked lists will likely need RAM allocated dynamically.

Here’s a reminder of memory allocation done behind the scenes.

  • Variables declared globally. I.e. outside of functions. RAM is allocated for these when the program runs and remains in use until the program finishes.
  • Variables declared inside a function. RAM is allocated for these when the function is entered and the memory allocated is freed up when the function exits.

Dynamic variables

This is a general name for variables that are allocated memory at runtime i.e. pointers. Not all pointers need to have memory allocated. For example when you set a pointer to point to a variable, that variable will already exist and no allocation is needed.

Here’s a reminder of earlier tutorials on pointers.

Here are some cases where no RAM needs to be allocated to pointers because the pointer is initialized. Remember, a pointer is just a variable that holds a memory address.

int a;
int* b = &a;
char* name = "My name";

Here both pointers b and name, point to objects in RAM. One points to the location of variable a, the other points to the text string “my name” where it is located in RAM.

Allocating RAM

For this we ned to use the function malloc().  This is defined as

void *malloc(size_t size);

The type size_t is an unsigned int that can hold the size of a largest object possible. The sizeof() function returns the size of a type or variable in size_t.

The function malloc returns a void pointer, so its customary to cast it to whatever you are using.

Here’s an example program.

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

struct myArrayStruct {
	int bigarray[100000];
};

typedef struct myArrayStruct* pArrStruct;

pArrStruct Alloc(int numStructs) {
	pArrStruct mem= malloc(numStructs * sizeof(struct myArrayStruct));
	if (!mem) {
		printf("Malloc failed to allocate memory");
	}
	return mem;
}

int main() {
	pArrStruct ptrArray = Alloc(50);
        memset(ptrArray, 0, sizeof(struct myArrayStruct)*50);
        // do something with ptrArray
	free(ptrArray);
	return 0;
}

This declares a type myArrayStruct containing an array of 100,000 ints.  I’ve defined a type pArrStruct which is a pointer to a myArrayStruct. Next I’ve created a function Alloc which lets you specify how many myArrayStructs you want. It calls malloc() to allocate memory, checks that malloc succeeded in allocating this memory and then returns it.

If malloc() fails to allocate the memory requested it returns a null.

So in main, I call Alloc(50) to allocate enough memory to hold 50 of the myArrayStructs. It then sets every byte in it to 0 using the memset() function from the memory library.

Finally, to finish off, the function free() is called with ptrArray. This returns the RAM to the operating system. As a good rule of thumb you should have one matching free for every malloc.

If your program is going to do a lot of malloc calls, it may be easier to put them in a library and have it track every malloc, perhaps keeping a copy of every pointer in an array. At the end you call a library function which then loops through all the allocated memory blocks and frees each of them up.

Conclusion

I’ve kept this deliberately short. There are two other functions calloc which allocates a block of a specified size and then sets the value (so like malloc followed by memset() and realloc which lets you change the size of an allocated block, maintaining existing values. However make sure you are happy with malloc before using those.

(Visited 109 times, 1 visits today)