Sunteți pe pagina 1din 5

Lesson 6: Dynamic Memory Allocation Step 1 - An Introduction to Dynamic Memory Allocation Up until this time, we have used what

is referred to as static memory. Stati c memory means we reserve a certain amount of memory by default inside our progr am to use for variables and such. While there is nothing wrong with this, it mea ns that once we reserve this memory, no other program can use it, even if we are not using it at the time. So, if we have two programs that reserve 1000 bytes o f memory each, but neither program is running, then we have 2000 bytes of memory that is being completely wasted. Suppose we only have 3000 bytes of memory, but we already have our two programs that take 1000 bytes each. Now we want to load a program that needs 1500 bytes of memory. Well, we just hit a wall, because we only have 3000 bytes of memory and 2000 bytes are already reserved. We can't lo ad our third program even though we have 2000 bytes of memory that isn't even be ing used. How could we possibly remedy this situation? If you said Dynamic Memory Allocation, then you must have read the title of this lesson. That's right. We are going to use dynamic memory to share the memor y among all three programs. Dynamic memory won't fix everything. We will always need an amount of finite static memory, but this amount is usually much less than we need. This is why w e still have static memory. So, let us imagine a new scenario. We have changed our first two programs to use dynamic memory allocation. Now they only need to reserve 100 bytes of memor y each. This means we are now only using 200 bytes of our 3000 total memory byte s available. Our third program, which requires 1500 bytes of memory can now run fine. Step 2 - The Basics of Dynamic Memory Allocation Now that we have covered why we would want to use dynamic memory allocation, how do we go about doing it? Well, that's easy! We have predefined functions th at let us perform these tasks. The two functions we will be employing in our dynamic memory allocation task s are malloc() and free(). malloc() meaning memory allocation, and free, well, t hat should be obvious. Our malloc() function returns a pointer to the memory blo ck we requested. Remember pointers from the last lesson? I told you we weren't d one with them yet. Let's discuss the syntax of malloc(). It takes a single argument, a long int eger representing the number of bytes we want to allocate from the heap. (Note: the heap is what we call all the memory we don't reserve by default) So, for exa mple, to allocate memory for an array of characters for a 40 character string, w e would do malloc(40); There's more to it, obviously, but we'll cover that. To allocate memory though, we must have a pointer so we can know where the m emory will be at when it gets allocated. Let's look at a small code example: char *str = (char *)malloc(40); ring This may look a little weird, because it uses a concept we haven't worked wi th before called "type casting". C has the ability to convert from one type of v ariable to another by using what are called type cast operators. The syntax is s imple, put the variable type you want to convert to inside parentheses. See, it' s easy. So, because we want to convert the memory into a character pointer, whic // allocate memory for a 40 character st

h is specified by the type char *, we put char * in parentheses. Then C will giv e us a character pointer to the memory. This is very easy to do when a character pointer is involved. The important thing to note here is what malloc() returns to us. Because malloc() doesn't care how the memory we allocate will be used, ma lloc() just returns a pointer to a series of bytes. It does this by using a void pointer. Void pointers are just like character pointers, or integer pointers, o r any other kind of pointer with one special difference: we do not know what the size of the void pointer is. There is no way to increment or decrement a void p ointer. In fact, we can't do much of anything with a void pointer except acknowl edge its existence until we convert (type cast) it to another variable type. Characters are by definition 1 byte, and malloc always allocates in multiple s of a single byte. Other types are more than 1 byte. Rather than remembering ho w many bytes an int variable takes on a system, we can use the sizeof operator. Let's see an example. char *str = (char *)malloc(40 * sizeof(char)); 40 character string // allocate memory for a

This looks very similar to what we had above, with one important exception, the sizeof(char) multiplier. This is a new operator, and another very important one in C. The sizeof() operator will tell us the size of any variable or structu re in our program. The one thing to keep in mind when using sizeof() is that the size of a pointer is how many bytes it takes to store the pointer, not the size of the memory block the pointer is pointing at. There is no need to know that i nformation. In allocating memory like this, we know we have 40 characters instea d of 40 bytes (even though they are technically the same). There is a difference between 40 integers and 40 bytes, and 40 long integers especially. Now that we have taken a look at how the malloc() function works, let's take a look at its companion function, free(). The free() function is basically the exact opposite of malloc(). So, instead of assigning a pointer the value returne d, we give the function the pointer we got from malloc(). So, if we have the *st r pointer we allocated above, to free that memory, we just need to call free wit h the pointer as an argument. free(str); // free the memory allocated by malloc() You may be wondering how the free() function knows how much memory to free u p, since we didn't tell it how much memory we allocated. Well, the short answer is: you don't need to worry about that. The system will take care of such minuti a for us. The long answer is, well, long, and complicated, so I don't want to ta lk about it. Most modern systems will free allocated memory at the completion of the prog ram. The AMS is not one of these systems. If you don't free the memory you alloc ate, your calculator will lose memory until it is reset. Step 3 - The Many Uses of malloc() Start TIGCC and create a new project. Create a new C Source File called mall oc. Edit the file so that it looks like this: malloc.c #include <tigcclib.h> void _main(void) { int loop; unsigned long int *array;

// the integer array pointer

// clear the screen for printf() clrscr(); // allocate the array or exit with an error if ((array = (unsigned long int *)malloc(45 * sizeof(unsigned long int))) == NULL) { DlgMessage("DMA Failure","Unable to allocate integer array space",BT_OK, BT_NONE); return; } // get the first two numbers in the Fibonacci sequence -- I start at 1, not 0 array[0] = 1; array[1] = 1; // setup the array with the first 45 numbers in the sequence for (loop = 2; loop < 45; loop++) { array[loop] = array[loop - 1] + array[loop - 2]; } // display the intro message printf("The Fibonacci Sequence:\n"); printf("Press a key to begin!\n\n"); ngetchx(); // loop through the array and print out the numbers in the sequence for (loop = 0; loop < 45; loop++) { // print the number - lu = long unsigned printf("%lu\n",array[loop]); // if we've printed 8 numbers, pause to see the result if (((loop % 8) == 0) && loop != 0) { printf("Press any key...\n"); ngetchx(); } } // free up the memory used by the integer array free(array); // wait for user input before exiting the program ngetchx(); } Step 3a - Compile and Run the Program Build the project and send it to TiEmu. It will look like this: TI-89 AMS 2.05 malloc.89z TI-92+ AMS 2.05 malloc.9xz Step 3b - Programmatic Analysis Okay. I know this wasn't the best example, but I couldn't think of anything good to do. Anyway, let's try to get through it. Although thinking about how man y computer science classes I took that used factorial as an example program, may be it's not that bad. int loop;

unsigned long int *array;

// the integer array pointer

We have our variable declarations. Remember that there is very little differ ence between arrays and pointers, so once we have space for our pointer, it will be an array. // allocate the array or exit with an error if ((array = (unsigned long int *)malloc(45 * sizeof(unsigned long int))) == NULL) { DlgMessage("DMA Failure","Unable to allocate integer array space",BT_OK, BT_NONE); return; } One thing I forgot to mention about Dynamic Memory Allocation is, unlike sta tic memory which is reserved by default (so you won't be able to send the progra m unless you have enough memory), dynamic memory must be allocated at runtime. T hat being said, there may not be enough memory available to fill the request. So , we must always check that our memory was actually allocated to us by checking the pointer against a NULL value. The NULL value basically says, "I am not point ing at anything". And, if we are not pointing at anything after we finish our ma lloc() call, then we don't have enough memory to run this program. We should dis play some kind of error message and exit the program. To exit a program from the main() have seen return when we are sending ction is no different, except that we ype of the main function is void. So, ecific value. method, we can use the return keyword. You back a value from a function. The main fun do not return a value because the return t we can use return without returning any sp

This being done, if we haven't exited our program, then we must have gotten the memory we requested. So, let us continue. // get the first two numbers in the Fibonacci sequence -- I start at 1, not 0 array[0] = 1; array[1] = 1; Since this example deals with the Fibonacci Sequence, we need to initialize the base cases of that sequence. If you haven't seen the Fibonacci sequence befo re, it runs like this. The first two numbers are 1 and 1. Every number after the first two numbers are the sum of the previous two numbers. So we have 1, 1, 2 ( 1 + 1), 3 (1 + 2), 5 (2 + 3), 8 (3 + 5), 13 (5 + 8), etc. Remember that since ar rays are just a special way of using pointers, we can use array notation for acc essing our pointer memory. We could have done the same thing by using this code: *array = 1; // set the first array node to 1 *++array = 1; // set the second array node to 1 But array notation is more readable. // setup the array with the first 45 numbers in the sequence for (loop = 2; loop < 45; loop++) { array[loop] = array[loop - 1] + array[loop - 2]; } Okay, our first big loop sets up all the values in our limited segment of th e Fibonacci sequence (the first 45 values). Since we allocated space for a 45 no de array, we will have no problem storing this. As per our definition of the seq uence, each value is the sum of the previous two values, so we use a simple assi

gnment statement (=). // display the intro message printf("The Fibonacci Sequence:\n"); printf("Press a key to begin!\n\n"); ngetchx(); You should know how printf() works by now, especially in this limited exampl e. We are just displaying a short message on the screen. // loop through the array and print out the numbers in the sequence for (loop = 0; loop < 45; loop++) { // print the number - lu = long unsigned printf("%lu\n",array[loop]); // if we've printed 8 numbers, pause to see the result if (((loop % 8) == 0) && loop != 0) { printf("Press any key...\n"); ngetchx(); } } Our next big loop prints out all the values in our sequence. We could have d one this while we were assigning our values to the sequence, but a real program would store the values in the array and access them later, so, this is a little closer to something real (okay, that's a stretch, but stay with me). The loop is fairly simple, we use printf() to display our values on the scre en because printf() is easy to use and will scroll the lines on the screen for u s automatically. Remember that the %lu format specifier is used for printing lon g unsigned integers, which is what we have in our array. The \n is our key for a new line. The last segment of this loop pauses the screen after 8 lines of output. We want to give the user a chance to see the results. We introduce another operator here, the modulo operator. Modulo gives us the remainder part of integer divisi on. So, if a number is evenly divided by 8 (loop modulo 8), then we will enter o ur if-clause. But we have to take care of one more condition. Remember that 0 mo dulo anything is always 0, and we don't want to pause after we print the first n umber, so we will make the condition also require that the loop counter is not 0 (the first node in the array). So, if both of these conditions are satisfied, t hen we print a short pause message and wait for the user to press a key. Simple, no? // free up the memory used by the integer array free(array); Okay, the last line of our program is possibly the most important when deali ng with dynamic memory allocation. Never ever forget that you must always free u p the memory you allocated before you exit the program. If the program exits wit hout freeing up the memory, it will be reserved forever. Worse than that, on the TI-89/92+/V200, there are a limited number of handles available to dynamic memo ry allocation, and once those handles are gone, we can't allocate any more dynam ic memory. The only way to get these handles and memory free if you don't free t hem before you exit the program is to reset the calculator, because the AMS does not do garbage collection for you. As long as you remember that one important rule, you shouldn't have a proble m with dynamic memory allocation.

S-ar putea să vă placă și