Last Updated:

C++ :Dynamic memory allocation | Lists | Examples

 

1. Dynamic memory allocation

Statically distributed variables exist either for the entire lifetime of the program or for the lifetime of the function in which they are declared (for local variables). Sometimes it becomes necessary to manage memory allocation dynamically while the program is running, for example, if we do not know exactly how much memory we will need, or for more flexible memory management so as not to take up memory that is not really needed.

Memory allocation is carried out by the function void
*malloc(size_t size);

The function prototype is located in the <stdlib.h> and <malloc.h> files.

This function allocates memory, the amount of which in bytes is specified as a parameter of the function. The function returns the address of the allocated memory, or NULL if the memory cannot be allocated. NULL is a special constant that is an invalid pointer.

The function returns a pointer to the empty type void *, which can be converted to any type and must be converted to the desired type. Be sure to check the result returned by the function!

There are also two more functions that allow you to make memory allocation more flexible:
void *calloc(size_t numsize_t size); void *realloc(void *memblocksize_t size);

The first function allocates memory for an array of elements, each of which has a size of . Array elements are initialized with zeros. numsize

The second function changes the size of the block previously allocated by the malloccalloc or realloc functions. The parameter contains the address of the block to change, and the parameter contains the required block size. The position of the block in RAM may change, and the contents will be copied. memblocksize

After there is no need for dedicated memory, you need to release it:
void free(void *memblock);

void free(void *memblock);

p = (int *)malloc(sizeof(int)); Using the sizeof operation, we determine the size of a variable of type int
if (!p)
  { printf("Not enough memory\n"); return; }
...
free(p);
 

In C++, new operators have been introduced to allocate and release dynamic memory: new and delete.

int*p;
 
p = new int; Allocate memory for a single variable of type int
deletep;
  Free up allocated memory
p = new int[10]; Memory allocation for an array of 10 elements of type int
delete[]p;
 

When using the new and delete operators, you must also check whether memory has been allocated. Typically, in the event of an error, the new operator throws an exception bad_alloc, but you can change its behavior so that the value 0 is returned in the event of an error.

#include <new>
int*p;
try
  { p = new int; }
catch(std::bad_alloc)
  { printf("Not enough memory\n"); return; }
...
deletep;
  To use bad_alloc and nothrow
p = new(std::nothrow) int[10];
if (!p)
  { printf("Not enough memory\n"); return; }
...
delete[]p;
 

2. Lists

A unidirectional list is a structure whose element contains the address of the next item. In the last element, the value of a special null constant is written to this address to indicate the end of the list. The address of the first element must be stored in a special variable.

Because each item must contain an information part and the address of the next item (which are generally of a different type), structures are used to store list items.

There are two main ways to build lists: by adding items to the beginning of the list and by adding items to the end of the list. The first method is simpler, but the items in the list are arranged in reverse order. If you want the list items to be arranged in a straight order, you must use the second method.

struct S
  {char str[21];
    int a;
    struct S *next;
   };

struct S *begin, *cur, *prev;
  Add items to the top of the list
cur = NULL;
while (!feof(in))
  { begin = (struct S *)malloc(sizeof(struct S));
    if (begin == NULL)
     { printf("Insufficient memory\n");
       fclose(in); fclose(out); return;
      }
    fscanf(in, "%s%d", begin->str, &(begin->a));
    begin->next = cur;
    cur = begin;
   }
  Add items to the end of the list
begin = (struct S *)malloc(sizeof(struct S));
if (begin == NULL)
  { printf("Insufficient memory\n");
    fclose(in); fclose(out); return;
   }
fscanf(in, "%s%d", begin->str, &(begin->a));
begin->next = NULL;
prev=begin;
while (!feof(in))
  { cur = (struct S *)malloc(sizeof(struct S));
    if (cur == NULL)
     { printf("Insufficient memory\n");
       fclose(in); fclose(out); return;
      }
    fscanf(in, "%s%d", cur->str, &(cur->a));
    cur->next = NULL;
    prev->next = cur;
    prev=cur;
   }
 

3. Examples

Example 1. Dynamic array distribution.

 

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

void main(int argc, char *argv[])
{ double *a, *p, *end;
  double s;
  int n, i;
  FILE *file;

  if (argc < 2)
   { printf("Not enough parameters!\n");
     return;
    }
  if ((file = fopen(argv[1], "r")) == NULL)
   { printf("Unable to open file '%s'\n", argv[1]);
     return;
    }
  if (fscanf(file, "%d", &n) < 1)
   { printf ("Error reading from file '%s'\n", argv[1]);
     fclose(file);
     return;
    }

// Use one of two memory allocation options
  if ((a = (double *)malloc(n * sizeof(double))) == NULL)
   { printf("Out of memory!\n");
     fclose(file);
     return;
    }
  if ((a = (double *)calloc(n, sizeof(double))) == NULL)
   { printf("Out of memory!\n");
     fclose(file);
     return;
    }

  for (i = 0; i < n; i++)
   if (fscanf(file, "%lf", &a[i]) < 1)
    { printf ("Error reading from file '%s'\n", argv[1]);
      fclose(file);
      return;
     }
  fclose(file);

// The usual way to process an array
  for (s = 0, i = 0; i < n; i++)
   s += a[i];
  printf("Sum is %lf\n", s);

// Using a pointer to access array elements
  for (s = 1, p = a, end = p + n; p < end; p++)
   s *= *p;
  printf("\Product equals %lf\n", s);

  free(a); // Free allocated memory
 }

 

Example 2. Working with the list

#include <stdio.h>
#include <conio.h>
#include <malloc.h>
#include <string.h>

struct S
{char str[21];
  int a;
  struct S *next; // You can declare a pointer to a structure that has not yet been declared
 };

void main(int argc, char *argv[])
{ struct S *begin, *cur, *prev;
  int a, check = 0;
  char str[21] = "";
  FILE *in, *out;
  charans;

  if (argc < 3)
   { printf("Too few arguments.\n"); return; }
  if ((in = fopen(argv[1], "r")) == NULL)
   { printf("It is impossible to open file '%s'.\n", argv[1]);
     return;
    }
  if ((out = fopen(argv[2], "w")) == NULL)
   { printf("It is impossible to open file '%s'.\n", argv[2]);
     fclose(in); return;
    }

  // Build the list by adding elements to the end. The first element is entered separately
  begin = (struct S *)malloc(sizeof(struct S));
  if (begin == NULL)
   { printf("Insufficient memory\n");
     fclose(in); fclose(out); return;
    }
  fscanf(in, "%s%d", begin->str, &(begin->a));
  begin->next = NULL;
  prev=begin;
  while (!feof(in))
   { cur = (struct S *)malloc(sizeof(struct S));
     if (cur == NULL)
      { printf("Insufficient memory\n");
        fclose(in); fclose(out); return;
       }
     fscanf(in, "%s%d", cur->str, &(cur->a));
     cur->next = NULL;
     prev->next = cur;
     prev=cur;
    }
  fclose(in);

  printf("Use Str for search? "); ans = getche();
  if (ans == 'y' || ans == 'Y')
   { printf("\nInput string for search: "); scanf("%s",str); }
  printf("\nUse A for search? "); ans = getche();
  if (ans == 'y' || ans == 'Y')
   { check = 1; printf("\nInput A: "); scanf("%d", &a); }

  // Output elements that satisfy the condition
  for (cur = begin; cur; cur = cur->next)
   if ((!*str || strcmp(str, cur->str) == 0) &&
       (!check || a == cur->a))
    fprintf(out, "%-30s %3d\n", cur->str, cur->a);

  // Removing elements that do not satisfy the condition. The address of the previous element will be needed when deleting
  for (prev = NULL, cur = begin; cur; )
   if ((*str && strcmp(str, cur->str) != 0) ||
       (check && a != cur->a))
    if (prev == NULL) // If you need to remove the first element
     { begin = cur->next;
       free(cur);
       cur = begin;
      }
    else // Removing non-first element
     { prev->next = cur->next;
       free(cur);
       cur = prev->next;
      }
   else // If you don't need to delete, just change the pointers
    { prev = cur; cur = cur->next; }

  for (cur = begin; cur; cur = cur->next)
   fprintf(out, "%-30s %3d\n", cur->str, cur->a);
  fclose(out);

  // Freeing the memory allocated for the list
  for (cur = begin; cur; )
   { prev = cur;
     cur = cur->next;
     free(prev);
    }
  start = NULL;
 }