-=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- (c) WidthPadding Industries 1987 0|447|0 -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=- -=+=-
SoCoder -> Article Home -> Advanced Techniques


 
Phoenix
Created : 10 July 2008
Edited : 30 October 2008
Language : Basic

Dynamic Memory in C

Explanation of the cryptic malloc()

Introduction

Last night I was in the MudChat, and Spinal was wondering how the malloc() function in C works. I tried to explain, but I probably wasn't elaborate enough. So I figured that he probably isn't the only one who wonders how to work with memory allocation, and therefore I wrote this article.

Prerequisites

This isn't a C tutorial. I assume that you have a basic understanding of C and some knowledge of pointers.

The Stack and the Heap

There are two ways to work with memory in C; on the stack and on the heap. An example of memory allocated on the stack can be seen here:



"foo" needs to be stored in memory, and when variables are defined the way pictured above they are stored on the stack. The stack can be seen as a temporary storage place for memory, because the variable is removed when it goes out of scope.

Those curly braces - {} - define the beginning and the end of a scope. When a variable is allocated on the stack inside a scope, it "expires" when the } is reached. This shows a potential limitation of the stack:



"foo" may or may not be a 5, because when returnFive's scope ends, its stack memory is freed. When memory is freed, its content isn't necessarily removed, but it is no longer reserved space in memory. The operating system will think that the memory can be reused for other purposes. So the five will remain in memory for a while, but can change at any time because other things might start using that particular block of memory.

So how do we overcome this problem? We work on the heap.

Dynamic Memory Allocation

This is where we get to the good stuff. Dynamic memory allocation (heap memory) is what we use to solve the issue of the previous example. I'll show some code first:



This way works around the limitations of the stack. We tell the program that we want enough memory for an integer (usually four bytes), so it searches all the blocks of memory it has until it finds a place where there are four bytes available, and returns a pointer to that space. That is, unless it is impossible to find such a place. When that happens, it just returns zero. The pointer is actually created on the stack, and it is therefore removed when it reaches the end of the scope. But it is only a pointer, and not the data it points to. Since we return a copy of the pointer with "return bar", there is no loss of data. The block of memory still exists and its address is returned into foo in main().

The memory remains until we call free(), which tells the program that the memory is no longer in use and can be utilized by other operations -- perhaps another allocation on the heap.

The Syntax of malloc()

At first, the syntax of malloc() can look a bit confusing so I'll walk you through it.

malloc() returns a pointer, and therefore you need to have a pointer where you store the address to the memory block. Let's take a char as an example:



Since it returns a void pointer (pointer to anything), the return value needs to be casted to your data type:



Then you need to define the size of your memory block. This is usually accomplished using the sizeof() function, which returns how many bytes large the data type passed to it is. For example, sizeof(char) commonly returns 1, since it is one byte large.



Often though, you want to store more than just a couple of bytes. This can be accomplished by multiplying sizeof(data_type) by the amount of elements you want. For example, let's say we wanted to store the word "Hi" (containing two letters) inside our heap memory.



As seen above, you can access each char individually by using square braces. This is because heapMemory only points to the address of the first element of the memory block (&heapMemory[0]), as oposed to the whole block. Pointers don't contain any information about the size of the memoory block it points to. The same principle can be applied to pretty much any data type:



Conclusion

I hope that that was understandable -- if not, feel free to ask and I'll try to explain even more.

(I'm eagerly awaiting a thousand corrections from Agent Smith)

 

Comments


Thursday, 10 July 2008, 11:38
mike_g
I havent really read this article through yet, but malloc.h is included as part of stdlib
Thursday, 10 July 2008, 11:55
Phoenix
Thanks, I didn't know that. I'll correct it.
Friday, 11 July 2008, 20:41
JL235
There are also libraries and tools such as dmalloc that can be used to help debug all those memory leaks you'll be making with malloc.