Heap Memory

From Nutwiki
Revision as of 17:02, 27 October 2016 by Harald (Talk | contribs) (1 revision imported)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Test Environments

Hardware Comments Nut/OS
4.8.3
Nut/OS
4.8.7
Ethernut 1.3 H OK
Binaries
Compiler: AVR-GCC 4.3.2
OK
Binaries
Compiler: AVR-GCC 4.3.2
Ethernut 2.1 B OK
Binaries
Compiler: AVR-GCC 4.3.2
OK
Binaries
Compiler: AVR-GCC 4.3.2
Ethernut 3.0 E OK
Binaries
Compiler: ARM-GCC 4.3.3
OK
Binaries
Compiler: ARM-GCC 4.3.3

Description

This example demonstrates how to allocate heap memory, assign it to your variables and finally free the used memory again.

Source Code

<source lang="c">

  1. include <dev/board.h>
  2. include <stdio.h>
  3. include <stdlib.h>
  4. include <string.h>
  5. include <io.h>
  1. include <sys/timer.h>
  2. include <sys/heap.h>

int main(void) {

   unsigned long baud = 115200;
   char foobar[20] = "Hello world!";
   uint16_t *myvar;
   uint16_t *myarray;
   char *mystring;
   NutRegisterDevice(&DEV_DEBUG, 0, 0);
   freopen(DEV_DEBUG_NAME, "w", stdout);
   _ioctl(_fileno(stdout), UART_SETSPEED, &baud);
   printf("Heap memory available: %d bytes\n", (int) NutHeapAvailable());
   /* allocate some RAM */
   myvar = malloc(2);
   *myvar = 27;
   printf("Our freshly allocated variable contains: %d\n", *myvar);
   printf("\nHeap memory available: %d bytes\n", (int) NutHeapAvailable());
   myarray = calloc(3, 2);
   myarray[0] = 30;
   myarray[1] = 97;
   myarray[2] = 21;
   printf("This works for arrays as well:\n1. %d\n2. %d\n3. %d", myarray[0], myarray[1], myarray[2]);
   printf("\nHeap memory available: %d bytes\n", (int) NutHeapAvailable());
   mystring = strdup(foobar);
   printf("\nAnd now we can output the string '%s' without worrying about the size.\n", mystring);
   printf("\nHeap memory available: %d bytes\n", (int) NutHeapAvailable());
   printf("Let's free the memory again...\n");
   free(myvar);
   free(myarray);
   free(mystring);
   printf("\nHeap memory available after freeing: %d bytes\n", (int) NutHeapAvailable());
   for (;;);
   return 0;

} </source>

Details

<source lang="c"> unsigned long baud = 115200;

char foobar[20] = "Hello world!";

uint16_t *myvar; uint16_t *myarray; char *mystring;

NutRegisterDevice(&DEV_DEBUG, 0, 0);

freopen(DEV_DEBUG_NAME, "w", stdout); _ioctl(_fileno(stdout), UART_SETSPEED, &baud); </source>

We set up the debug device and declare a string and 3 pointers. The string will be used as is, the pointers will hold the addresses of the memory blocks we are about to allocate.

<source lang="c"> printf("Heap memory available: %d bytes\n", (int) NutHeapAvailable()); </source>

We print our available memory to the screen. NutHeapAvailable returns the number of bytes available. Since it returns size_t, we have to cast it to int to avoid compiler warnings.

<source lang="c"> /* allocate some RAM */ myvar = malloc(2);

  • myvar = 27;

printf("Our freshly allocated variable contains: %d\n", *myvar); </source>

Here we allocate space for a single variable, the only parameter malloc takes is the number of bytes it should allocate. After that we can use the dereferenced variable as usual and assign a value to it. Since we have allocated 2 bytes, this can be used as uint16_t, 2 characters or whatever you want to use it as. malloc always returns a void* to the allocated memory block so how it is used is entirely up to you.

<source lang="c"> myarray = calloc(3, 2); myarray[0] = 30; myarray[1] = 97; myarray[2] = 21; printf("This works for arrays as well:\n1. %d\n2. %d\n3. %d", myarray[0], myarray[1], myarray[2]); </source>

Using calloc you can do the same thing for arrays. The first parameter is the number of elements, the second number is the length of each element. That means we allocate 6 bytes in total. We don't even have to dereference those since the [] operator takes care of finding the correct memory offset for us already. (This is not related to calloc but to how arrays work in general but it is especially useful here.)

<source lang="c"> mystring = strdup(foobar);

printf("\nAnd now we can output the string '%s' without worrying about the size.\n", mystring); </source>

Now this works slightly different but in the same way. The string foobar was declared at the top, remember? Using strdup we can now copy that string to a char * without making any considerations about the string length! This will obviously fail if there's not enough RAM free to hold our new string but apart from that it will always allocate a string of exactly the required length. The main difference between strdup and <source lang="c"> mystring = malloc(sizeof(foobar)); memcpy(mystring, foobar, sizeof(foobar)); </source> is that strdup will only copy until it reaches a NULL character. A normal string is always terminated with such a NULL character (you can't see it since it is a control character but it is there.) and C will automatically add that character if you declare a string like this: <source lang="c"> char foobar[20] = "Hello world!"; </source>

Neat, eh?

<source lang="c"> free(myvar); free(myarray); free(mystring); </source> It's common sense to clean up your things after you're done but with malloc and the like this it is ESPECIALLY IMPORTANT since the memory will not be freed automatically afterwards. Free takes care of this for us.

Output

<source lang="text"> Heap memory available: 67104296 bytes Our freshly allocated variable contains: 27

Heap memory available: 67104288 bytes This works for arrays as well: 1. 30 2. 97 3. 21 Heap memory available: 67104276 bytes

And now we can output the string 'Hello world!' without worrying about the size.

Heap memory available: 67104256 bytes Let's free the memory again...

Heap memory available after freeing: 67104296 bytes </source> Note: The available heap memory depends on the RAM your board has. This output was generated with an EIR which has 64MB.

See also





Template:Languages