Never Stop Writing Code

To a certain extent, coding is something that you never completely forget. Although you may be a little slower after a break, once the problem-solving part of your brain fires up, you will still have the skills and knowledge to do the things you have always done.

However, coding is also a lot like the knowledge of a foreign language.

Read moreNever Stop Writing Code

Understanding Pointers (with Lego) Part 1

Ahhh pointers.

I’ve been wanting to write a series of posts on pointers for a long time. When I’ve finished, I’ll upload a complete PDF eGuide. In the meantime, enjoy 🙂

Pointers.

A concept that some programmers avoid through fear, others abuse through ignorance, and yet others manage to use with grace and efficiency.

Every programmer who does more than dabble in C and C++ needs to understand this subject. Properly.

This is Part 1 of a multi-part series, and there will be a lovely quiz at the end, which I expect you will all get 100% on after reading my posts, right?

Let’s crack on.

Read moreUnderstanding Pointers (with Lego) Part 1

Dynamic Memory in C (malloc, calloc, realloc, free)

Let’s take a look at the four methods that allow us to utilize dynamic memory in C. Dynamic memory just means we are using memory on the heap, instead of on the stack.

Why would you want to use dynamic memory?

You might want to create a variable or object that persists beyond the scope of the function it is created in (i.e. to share it between functions). The only way to do this is to create it dynamically, and then remember to deallocate it at a later point. Alternatively, you might not know the size of something you are using until runtime (e.g. reading in a file), in which case the heap is a better place to store your data. Why? Because the size of the stack is limited and it may be too small for unknown data processed at runtime.

How do you dynamically allocate in C?

There are three functions for memory allocation (plus one for deallocation). Each allocator returns a void* to the memory that has been allocated, which can be cast to the appropriate type.

Let’s look at each in turn:

1. malloc

This is the most commonly used method. Simply pass in how big you want your memory to be (in bytes), and you get a pointer to that memory back. The memory is uninitialized. If it fails it returns NULL.

2. calloc

Instead of passing in a size, you tell calloc how many of a certain type of variable you are going to use. E.g. 10 ints, or 16 structs. The memory is initialized to zeros. If it fails it returns NULL.

3. realloc

This method resizes an existing block of memory and you can make your existing memory allocation bigger or smaller. It frees the existing block and returns a void* to the new block. If you pass in zero, it effectively frees the memory in question. If it fails it returns NULL (see the comments in the code below for why you should pay careful attention to how you use realloc).

And what do you do when you’re finished?

You call free, nice and easy, and your memory is released (although it is not “deleted” as such – the data may exist until something else overwrites it, or part of it, or until the program ends).

Note that calls to malloc, calloc and realloc set errno if they fail. You can find out how to use errno here!

Can I see an example?

Sure – here’s a little bit of code that uses all four methods so you can see them at work:

#include <stdlib.h>

#define BIG_NUMBER 1024
#define SMALL_NUMBER 16

struct msg
{
	int code;
	char message[BIG_NUMBER];
};

int main(void)
{
	char* buffer;
	struct msg* messagelist;

	/* Allocate some memory from the heap */
	buffer = (char*)malloc(BIG_NUMBER);
	if (buffer != NULL)
	{
		/* I can use the memory safely */
	}

	/* Reduce the size of the memory */
	char* smallbuffer = (char*)realloc(buffer, SMALL_NUMBER);
	if (smallbuffer != NULL)
	{
		/* I can use the memory safely */
	}

	/*******************************************
	 * NOTE: Look carefully at the realloc call above.
	 * If the call to realloc had failed and I had assigned
	 * it to the original buffer like so:
	 *     buffer = (char*)realloc(buffer, SMALL_NUMBER);
	 * then my buffer would have been set to NULL and I would
	 * not only lose access to the data that was stored
	 * there, but I'd create a memory leak too!
	 *******************************************/

	/* Allocate some memory from the heap */
	messagelist = (struct msg*)calloc(SMALL_NUMBER, sizeof(struct msg));
	if (messagelist != NULL)
	{
		/* I can use the memory safely */
	}

	/* Remember to clear up after myself */
	free(smallbuffer);
	free(messagelist);

	/* NOTE: I DON'T need to free the 'buffer' variable */
	/* because realloc already did it for me 🙂 */

	return EXIT_SUCCESS;
}