[C language] Detailed explanation of dynamic memory management

About dynamic memory allocation

Recall the memory allocation methods we learned before:

int val = 20;//在栈空间上开辟四个字节
char arr[10] = {
    
    0};//在栈空间上开辟10个字节的连续空间

When learning C language, we know that data structures are usually fixed size. Take the array as an example. Once the program is compiled, the size of the array and the number of elements are determined . Then the size of the data structure cannot be changed without modifying the program and compiling the program again. The summary is the following two characteristics:

  1. The space opening size is fixed.
  2. When declaring an array, the length of the array must be specified. Once the size of the array space is determined, it cannot be adjusted.

But the demand for space is not just the above-mentioned situations. Sometimes the amount of space we need can only be known when the program is running, so the method of creating space during compilation of the array is not sufficient.
So the C language introduced dynamic memory allocation, which allows programmers to apply for and release space themselves . The following will introduce how to dynamically open memory.

Introduction to malloc and calloc functions

The following is the definition of cplusplus pair malloc:

void* malloc (size_t size);

This function applies for a continuous space in memory and returns a pointer to this space. sizeThat is, the size of the memory space you want to apply void*for is the address of the first element of the requested memory. Because you don’t know the type, you use it void*. There are also the following points to note:

  • If the allocation is successful, a pointer to the allocated space is returned.
  • If the allocation fails, a NULL pointer will be returned, so the return value of malloc must be checked.
  • The type of the return value is void*, so the malloc function does not know the type of space to be opened. The user must decide by himself when using it.
  • If the size parameter is 0, the behavior of malloc is undefined by the standard and depends on the compiler.

Let’s take a look at the definition of cplusplus pair calloc:

void* calloc (size_t num, size_t size);

mallocIn fact, callocit is very similar to. rallocThe parameter in sizeis the size of each data type that you want to apply for, which numis the number of data types that you want to apply for. The total size of the application is num*size, in fact, it can be represented mallocby size. The other features are mallocsimilar, so I won’t introduce them in detail. Of course, there are differences
between the two , as follows:

  • malloc The only difference from the function is that each bytecalloc of the requested space is initialized to 0 before returning the address .

So if we want to initialize the dynamically applied memory space to 0, it is rallocmore convenient to use.

Dynamic memory recycling----free

In fact malloc, callocfunctions such as dynamically allocating memory actually allocate memory on the heap area. Since the memory space requested by these functions is not automatically reclaimed by the system , using such functions too frequently to open up space will lead to heap exhaustion. At this time, we need to actively release the opened space , so we introduce freea function. The function prototype is as follows:

void free (void* ptr);

The pointer here ptrpoints to the first address of our dynamically allocated memory . Only by pointing to the first address can the dynamically allocated memory space be completely released. There are two special cases regarding ptrpointers ;

  • If ptrthe space pointed to by the parameter is not dynamically allocated, freethe behavior of the function is undefined.
  • If the argument ptr is NULLa pointer, the function does nothing.

Two more things to note :

  1. After we release the opened space, the original pointer pointing to this space ptrstill stores the address here. In order to avoid accidentally assigning or dereferencing this pointer later, causing a wild pointer problem , after releasing the space, we also This pointer needs to be assigned NULL.
  2. When writing code, it is best to always have a pointer to this space. If there is no pointer to this space, then this space will not be accessible and freed. For programs, inaccessible space is also called garbage, and programs that leave garbage have memory leaks .
    Insert image description here

As shown in the figure above, the original pointer ppoints to the first memory block, and after the operation, pit points to the second memory block. So since there is no pointer pointing to the first memory block, this memory block can no longer be used. This is the garbage mentioned above, causing a memory leak .

realloc function introduction

Sometimes we find that the space we applied for in the past is too small, and sometimes we feel that the space we applied for is too large. In order to apply for memory reasonably, we must make flexible adjustments to the memory size. At this time, reallocthe function can adjust the dynamically allocated memory size .
The function prototype is as follows:

void* realloc (void* ptr, size_t size);

The pointer ptrpoints to the memory address to be adjusted sizeand the adjusted memory size. The return value is the starting address of the adjusted memory.
Case 1: There is enough space after the original space
. When it is case 1, if you want to expand the memory, just add space directly after the original memory. The data in the original space will not change.
Insert image description here

Case 2: There is not enough space after the original space
. When it is case 2 and there is not enough space after the original space, the expansion method is: find another continuous space of appropriate size on the heap space to use. . In this way, the function returns a new memory address. In this case, for the data already in the original memory, this function will copy those data to the new memory , and the original memory will be released .
Insert image description here
There is also the problem of not being able to find the original memory space reallocdue to the pointer being assigned when the dynamic memory space fails to be opened . NULLWe generally create a new pointer to receive the address , and NULLthen assign it to the original pointer after judging that it is not correct, as follows:

int main()
{
    
    
     int* ptr=(int*)malloc(5*sizeof(int));
     int* p=(int*)realloc(10*sizeof(int));
     if(p != NULL)
          ptr = p;
     //......(代码)
     free(ptr);
     ptr = NULL;
     return 0;
}

Common dynamic memory errors

  1. Dereference operation on NULL pointer:
 void test()
 {
    
    
      int *p = (int *)malloc(INT_MAX/4);
      *p = 20;
      free(p);
 }

If the value in this code pis NULL, there will be a problem.

  1. Out-of-bounds access to dynamically allocated space:
 void test()
 {
    
    
      int i = 0;
      int *p = (int *)malloc(10*sizeof(int));
      if(NULL == p)
      {
    
    
           exit(EXIT_FAILURE);
      }
      for(i=0; i<=10; i++)
      {
    
    
           *(p+i) = i;//当i是10的时候越界访问
      }
      free(p);
 }
  1. Use free release for non-dynamically allocated memory:
void test()
{
    
    
     int a = 10;
     int *p = &a;
     free(p);
}

The one here ais opened in the stack area. If you use freethe release system, an error will be reported.

  1. Release the same dynamic memory multiple times:
void test()
 {
    
    
      int *p = (int *)malloc(100);
      free(p);
      free(p);//重复释放
 }

mallocThe dynamic memory space opened here is released repeatedly, and the system will also report an error.

  1. Use free to release a part of dynamically allocated memory:
 void test()
 {
    
    
      int *p = (int *)malloc(100);
      p++;
      free(p);
 }

Because ++the symbol will change the value of the variable, it pno longer points to the starting position of the dynamic memory. At this time, using freerelease will not release all the dynamic memory.

  1. Dynamically allocated memory and forget to release it (memory leak):
 void test()
 {
    
    
      int *p = (int *)malloc(100);
      if(NULL != p)
     {
    
    
          *p = 20;
     }
 }
 int main()
 {
    
    
      test();
      while(1);
 }

After calling test()the function, the opened memory space is not actively released. The same memory space in the stack area will be recycled after calling this function, so the opened space int* pcannot be found . This is the garbage mentioned above, and the garbage left mallocThe program has a memory leak . So remember that dynamically opened memory must be released!

Guess you like

Origin blog.csdn.net/2301_77404033/article/details/133247008