[Advanced C language] Those C/C++ points you must master - dynamic memory management (1)

insert image description here

Junxi_'s personal homepage

Be diligent and encourage the years to wait for no one

C/C++ game development


Hello, Mina-san, this is Junxi_, I wrote an article about the sequence table of data structures before, which quoted a lot of knowledge about dynamic memory development. Today I will take you to learn more about dynamic memory management. Very important knowledge, I guarantee that everyone will have a deeper understanding of this part after reading it!
Well, without further ado, let's start today's study!

foreword

  • In fact, if you want to learn this part well, just master how to use the following four functions
    insert image description here
  • Let's introduce these functions in turn

1. Why dynamic memory allocation

  • We have learned this method of opening up memory before:
int val = 20;//在栈空间上开辟四个字节
char arr[10] = {
    
    0};//在栈空间上开辟10个字节的连续空间
  • But the above method of opening up space has two disadvantages:
    1. The size of space opening is fixed.
    2. When declaring an array, the length of the array must be specified, and the memory it needs will be allocated at compile time.
    But for space requirements,. Sometimes the size of the space we need can only be known when the program is running, which often leads to the space we open up on the stack space being too large or too small. Obviously, this way of opening up space cannot meet our needs.

Two. malloc and free

  • What we need to know is that when you open up a piece of space for no longer use, you must release it free and return it to the operating system. Therefore, we merge this piece together

1.malloc

  • The C language provides a dynamic memory allocation function:
void* malloc (size_t size);
  • This function applies for a contiguous available space from memory and returns a pointer to this space.
    If the allocation is successful, a pointer to the allocated space is returned.
    If the opening fails, a NULL pointer is 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 the opened space, and the user can decide by himself when using it.
  • 如果参数 size 为0,也就是开辟一块空间大小为0的空间,malloc的这种行为是标准是未定义的,取决于编译器。

2.free

  • C language provides another function free, which is specially used to release and reclaim dynamic memory. The function prototype is as follows:
void free (void* ptr);
  • The free function is used to release dynamically allocated memory.
    If the space pointed to by the parameter ptr is not dynamically opened, the behavior of the free function is undefined.
    If the parameter ptr is a NULL pointer, the function does nothing.
  • Both malloc and free are declared in the stdlib.h header file.
  • Well, let's take a look at the effect in combination with specific examples.
#include <stdio.h>
#include <stdlib.h>
 int main()
{
    
    
    	//int arr[10];
    	int* p = (int*)malloc(40);//开辟40个字节的整形空间,把返回的开辟好空间的起始地址保存在p中
    
    	if (p == NULL)//判断malloc开辟内存是否成功
    	{
    
    
    		perror("malloc");//如果没成功,通过perror来报错
    		return 1;
    	}
    	//开辟成功
    	int i = 0;
    	for (i = 0; i < 10; i++)
    	{
    
    
    		printf("%d\n", *(p + i));//打印一下此时p中空间存储的内容
    	}
    
    	free(p);//用完后释放空间,把开辟的空间返回给操作系统
    	p = NULL;//将p置空
    	return 0;
 }

insert image description here

In addition to the points mentioned in the comments, there are several issues worth noting:

  • 1. Unlike the calloc mentioned later, malloc directly returns the starting address of the space after applying for the space, and will not initialize the content of the space, so the random value printed in the result is normal.
  • 2. About using free to release, if you do not release the space every time you open it after use, this is a typical memory leak. The memory space of the operating system is limited. Sooner or later, the space of your operating system will be filled with useless content, so remember to use free to release it when you are not using it after allocating the space.
  • 3. Regarding the point of setting p as a null pointer, some beginners may question the necessity of this part. In fact, this is very necessary. When we use free to release the opened space, this space no longer belongs to you If your p still points to this space, there is no doubt that p has become a wild pointer at this time, which is very dangerous, so it is very necessary!

Three.calloc

C language also provides a function called calloc, which is also used for dynamic memory allocation. The prototype is as follows:

void* calloc (size_t num, size_t size);
  • The function of the function is to open up a space for num elements whose size is size, and initialize each byte of the space to 0.
  • The only difference from the function malloc is that calloc will initialize each byte of the requested space to all 0s before returning the address.
    for example:
#include <stdio.h>
#include <stdlib.h>
int main()
{
    
    
int *p = (int*)calloc(10, sizeof(int));
if(NULL != p)
{
    
    
//使用空间
}
free(p);
p = NULL;
return 0;
}

insert image description here

  • Through the characteristics of calloc, it is not difficult to see that calloc can play a great role in some cases that require us to initialize the content of the applied memory space.

Four. realloc

  • The emergence of the realloc function makes dynamic memory management more flexible.
  • Sometimes we find that the space we applied for in the past is too small, and sometimes we feel that the space we apply for is too large. In order to use the memory reasonably, we need to flexibly adjust the size of the memory. Then the realloc function can adjust the size of the dynamically allocated memory.
    The function prototype is as follows:
void* realloc (void* ptr, size_t size);
  • ptr is the memory address to adjust
  • size New size after adjustment
  • The return value is the adjusted memory starting position.
  • On the basis of adjusting the size of the original memory space, this function will also move the data in the original memory to the new space.
    Realloc adjusts the memory space in the following two situations:

1. In-place expansion

  • This is the case when there is a large enough space after the original space
  • At this point, we only need to expand the capacity behind the original space and return to the expanded space

insert image description here
The extended memory directly adds space after the original memory, and the data in the original space does not change.

2. Remote expansion

  • When the space behind our original space is not enough, realloc will perform off-site expansion
  • The way to expand is: Find another continuous space of suitable size on the heap space to use. This function returns a new memory address

insert image description here

  • Since there are two situations when realloc expands capacity, we should pay attention to the following errors
#include <stdio.h>
int main()
{
    
    
    int* ptr = (int*)malloc(100);
    if (ptr != NULL)
    {
    
    
        //业务处理
    }
    else
    {
    
    
        exit(EXIT_FAILURE);
    }
    //扩展容量
    //代码1
    ptr = (int*)realloc(ptr, 1000);//这样可以吗?(如果申请失败会如何?)
    //代码2
    int* p = NULL;
    p = realloc(ptr, 1000);
    if (p != NULL)
    {
    
    
        ptr = p;
    }
    //业务处理
    free(ptr);
    return 0;
}
  • Let's compare the above two pieces of code
  • We found that in Code 1, if we directly assign the value of realloc to our ptr, if it is opened in a different place, our ptr will point to the start address of the new memory. When realloc fails to open at this time, because ptr points to If there is a change, we will not be able to find the previous memory space, so when using realloc, we need to judge whether the new space opened is successful like Code 2, and then assign realloc to our ptr when the opening is successful.

3. Common memory errors

1. Dereference operation on NULL pointer

void test()
{
    
    
int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}
  • If our malloc fails to open up memory, the address of NULL is stored in our p. Dereferencing NULL in C language is a standard undefined behavior, which will directly cause the program to report an error!

2. Out-of-bounds access to dynamically allocated spaces

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);
}


  • A very common mistake, we have opened up 10 spaces of int type in total, but the program is going to the 11th, an obvious mistake.

3 Use free to release non-dynamically allocated memory

void test()
{
    
    
int a = 10;
int *p = &a;
free(p);//ok?
}

  • None of our ps are dynamically opened up, the two are not the same concept, and there is no need for free.

4 Use free to release part of a dynamically allocated memory

void test()
{
    
    
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
  • Note that our free cannot release the dynamically opened space one by one. To release, we must release all the dynamically opened memory. If you want to release part of the memory, you need to reallocate a new memory block, copy the data you need to keep to the new memory block, and then use the function to release the original memory block. The following code
#include <stdlib.h>
#include <string.h>

int main() {
    
    
    // 分配动态内存
    char* ptr = malloc(10);

    // 检查内存是否成功分配
    if (ptr == NULL) {
    
    
        // 处理内存分配失败的情况
        return 1;
    }

    // 复制数据到新的内存块
    char* newPtr = malloc(5);
    memcpy(newPtr, ptr, 5);

    // 释放原始的内存块
    free(ptr);

    // 使用新的内存块进行操作

    // 释放新的内存块
    free(newPtr);

    return 0;
}

5. Multiple releases of the same dynamic memory

void test()
{
    
    
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}

  • It is meaningless to repeatedly release the space that has been released, so be careful not to write more

6. Dynamically open up 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);
}
  • Forgetting to use free after using the dynamically allocated space will cause serious memory leaks. As a result, this part of the memory can no longer be used by other programs. It may cause the program's memory consumption to increase continuously, eventually causing the program to crash or the system to become unstable.

Summarize

  • Today's content is over here. The basic knowledge of dynamic memory management is here. If you can learn all the above content, then you have mastered most of the content of dynamic memory management. After that, we will provide Let's explain a few related interview questions to deepen your understanding and introduce the knowledge about flexible arrays.

  • Well, if you have any questions, please ask me in the comment area or private message, see you next time!

It is not easy for a new blogger to create. If you feel that the content of the article is helpful to you, you may wish to click on this new blogger before leaving. Your support is my motivation to update! ! !

**(Ke Li asks you to support the blogger three times in a row!!! Click the comment below to like and collect to help Ke Li)**

insert image description here

Guess you like

Origin blog.csdn.net/syf666250/article/details/132047098
Recommended