[C Language] Detailed Explanation of Dynamic Memory Management

1. Why is there dynamic memory allocation

In the previous study, we learned 数据类型+变量名to apply for a space.

int a = 100;
int arr[10] = {
    
     0 };

The memory size of the space opened up in this way is fixed.
So how can the memory size of the application space be changed? ?
Then dynamic memory management is introduced here .


2. Introduction to dynamic memory functions

首先下面介绍函数的头文件都是 #include <stdlib.h> 

The following about the perror function and the strerror function are mentioned in the introduction of the strerror function .

1. malloc function

void* malloc (size_t size);

The malloc function can apply for a space and pass back the first address of the applied space as the return value.
Notice:
1.1 The return value of the malloc function : if the malloc function is successfully applied, it will return the first address of the space , and if the application is not successful, it will return NULL.
1.2 The use of malloc function : Since the person who designed the malloc function does not know which type of variable we apply for space to store , we will know which variable to store when we use it, so when using it, we must return the valuecastinto the type we need.

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

int main()
{
    
    
	//假设这里申请十个整形内存大小的空间
	int* p = (int*)malloc(10 * sizeof(int));

	//判断是否申请成功
	if (p == NULL)
	{
    
    
		printf("malloc:%s\n",strerror(errno)); 
		perror("malloc");//若申请失败则打印malloc失败的原因
		//这里strerror函数与perror函数的作业相同
		return 1;
	}
	
	//使用
	for (int i = 0; i < 10; i++)
	{
    
    
		p[i] = i + 1;
	}

	for (int i = 0; i < 10; i++)
	{
    
    
		printf("%d ", p[i]);
	}

	//释放
	//...

	return 0;
}

insert image description here
insert image description here

2. calloc function

void* calloc (size_t num, size_t size);

The calloc function can apply for space like the malloc function, but the calloc function can initialize all the requested space to 0.
Notice:
2.1 Parameters of the calloc function : two parameters are required, the first parameter is the requirednumber of elements, the second parameter is thememory size.
2.2 The return value of the calloc function : the same as the malloc function , the application returns the value of the spacefirst address, otherwise returns NULL.
2.3 Use of the calloc function : Like the malloc function , the return value needs to becastinto the type you need.

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

int main()
{
    
    
	int* p =(int*) calloc(10, sizeof(int));
	if (p == NULL)
	{
    
    
		perror("calloc");
		return 1;
	}

	//使用
	for (int i = 0; i < 10; i++)
	{
    
    
		printf("%d ", p[i]);
	}
	
	//释放
	//....
	return 0;
}

insert image description here
insert image description here

3. realloc function

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

The realloc function can adjust the space requested by the malloc function and the calloc function .

Notice:
3.1 Parameters of the realloc function : two parameters are required, the first parameter isThe address of the memory space needs to be adjusted, the second parameter isAdjusted memory size.
3.2 The return value of the realloc function : the same as the malloc function and the calloc function , the adjustment successfully returns the value of the spacefirst address, otherwise returns NULL.
3.3 Use of the realloc function : Like the malloc function and the calloc function , the return value needs to becastinto the type you need.
3.4 The realloc function can not only adjust the requested space, but when the first parameter of the realloc function NULLis , it can directly apply for a space just like the malloc function.

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

int main()
{
    
    
	int i = 0;
	//这里开辟5个int类型内存的大小的空间
	int* p = malloc(5 * sizeof(int));
	if (p == NULL)
	{
    
    
		perror("malloc");
		return 0;
	}
	//使用
	for (i = 0; i < 5; i++)
	{
    
    
		p[i] = i + 1;
	}

	for (i = 0; i < 5; i++)
	{
    
    
		printf("%d ", p[i]);
	}
	printf("\n");
	//这里将malloc函数开辟的5个int内存大小调整为10个
	int* ptr = realloc(p, 10 * sizeof(int));
	if (ptr == NULL)
	{
    
    
		perror("realloc");
		return 1;
	}
	//这里若realloc函数返回的值不为NULL
	p = ptr;
	for (i = 5; i < 10; i++)
	{
    
    
		p[i] = i + 1;
	}

	for (i = 0; i < 10; i++)
	{
    
    
		printf("%d ", p[i]);
	}

	//释放
	//...

	return 0;
}

insert image description here

3.5 The principle of the realloc function
(1) When the continuous space after the parameter address is larger than the size of the space to be adjusted, the realloc function will directly adjust the space directly behind the incoming address.
insert image description here
(2) When the continuous space after the parameter address is smaller than the space to be adjusted, the realloc function will apply for another continuous space , and return the first address of this continuous space as the return value, and the original space will be released .
insert image description here

4. free function

void free (void* ptr);

The free function can release the space created by dynamic memory.

Notice:
4.1 If the parameters of the incoming functionnot dynamically typedout, causing undefined behavior to occur, which may crash the program or produce other unexpected results.
4.2 If the parameter passed into the function is NULL, then the function does nothing.

3. Common dynamic memory errors

1. Dereference operation on NULL

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

int main()
{
    
    
	int* p = (int*)malloc(4 * sizeof(int));
	//如果这里p不进行判断,如果p为NULL
	//那么这里就是对NULL进行解引用操作
	*p = 4;
	free(p);
	p = NULL;
	return 0;
}

insert image description here

2. Cross-border access to the dynamically opened space

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

int main()
{
    
    
	int* p = (int*)malloc(5 * sizeof(int));
	//判断
	if (p == NULL)
	{
    
    
		perror("malloc");
		return 0;
	}
	int i = 0;
	//使用
	for (i = 0; i <= 5; i++)
	{
    
    
		p[i] = i; //当i = 5的时候越界访问
	}
	//释放
	free(p);
	p = NULL;
	return 0;
}

insert image description here

3. Release the non-dynamically opened space

int main()
{
    
    
	int a = 10;
	int* p = &a;
	free(p);
	return 0;
}

insert image description here

4. Use the free function to release part of the dynamically opened space

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

int main()
{
    
    
	int* p = (int*)malloc(5 * sizeof(int));
	//判断
	if (p == NULL)
	{
    
    
		perror("malloc");
		return 0;
	}
	p++;
	//释放
	free(p);
	p = NULL;
	return 0;
}

insert image description here

5. Multiple releases of a dynamically opened space

Notice: If the pointer is set to 0 after each release NULL, then there will be no problem here, and the subsequent free functionNULL will not perform any operations relative to the release .

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

int main()
{
    
    
	int* p = (int*)malloc(5 * sizeof(int));
	//判断
	if (p == NULL)
	{
    
    
		perror("malloc");
		return 0;
	}
	free(p);
	//释放
	free(p);
	p = NULL;
	return 0;
}

insert image description here

6. Dynamic memory is allocated but forgot to release (resulting in memory leaks)

void test()
{
    
    
	int* p = (int*)malloc(sizeof(int));
	if (p == NULL)
	{
    
    
		perror("malloc");
		return 0;
	}
	*p = 100;
}

int main()
{
    
    
	while (1)
	{
    
    
		test();
	}
	return 0;
}

insert image description here

Fourth, memory development

insert image description here

1. stack

The main function of the stack area is to store information such as temporary variables , function parameters , and function return addresses when the function is called .The stack area is used from the high address.

2. Heap

The heap area is mainly a space for storing dynamic memory development applications. Generally, it needs to be released after use. If you forget to release it, the space requested by dynamic memory development will be released by the operating system .The heap area is used from the lower addresses.

3. Data segment

The data segment is also called the data area and the static data area. It is used to store global variables and static data (variables modified by static), and is automatically recovered after the program ends.

4. Code snippet

The code segment is used to store binary code for executing instructions . It usually contains the program's instructions, constant values, and global variables.

Five, flexible array

1. Features of flexible arrays

1.1 The flexible array is in the structure, frontmustThere is at least one other type of structure member.
1.2 When the structure contains a flexible array, when sizeof()calculating the size of the structure, it is not counted as a flexible array.
1.3 The structure containing flexible array members uses malloc ()the function to dynamically allocate memory. When we open up a space, we must expect the size of the flexible array to facilitate the use of the flexible array.

2. The use of flexible arrays (code 1)

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

typedef struct node
{
    
    
	int a;
	char c;
	int arr[];
}Node;   //这里重命名了,但未使用

int main()
{
    
    
	//申请空间             结构体大小     +     10个整形大小
	struct node* p = (struct node*)malloc(sizeof(struct node) + 10 * sizeof(int));
	//这里相当于柔性数组申请了10 int类型大小的空间
	if (p == NULL)
	{
    
    
		perror("malloc");
		return 1;
	}

	//使用
	p->a = 10;
	p->c = 'v';
	for (int i = 0; i < 10; i++)
	{
    
    
		p->arr[i] = i + 1;
	}

	for (int i = 0; i < 10; i++)
	{
    
    
		printf("%d ", p->arr[i]);
	}

	//释放
	free(p);
	p = NULL;

	return 0;
}

insert image description here

3. Complete the function of flexible array without using flexible array (code 2)

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

typedef struct node
{
    
    
	int a;
	char c;
	int* pa;
}Node;

int main()
{
    
    
	//申请空间             结构体大小     +     10个整形大小
	struct node* p =(struct node*) malloc(sizeof(struct node));
	//判断第一次malloc是否成功
	if (p == NULL)
	{
    
    
		perror("malloc1");
		return 1;
	}

	//这里申请十个int类型大小的空间,并将申请的空间赋给p->pa
	p->pa = (int*)malloc(sizeof(int) * 10);
	//判断第二次malloc是否成功
	if (p->pa == NULL)
	{
    
    
		perror("malloc2");
		return 1;
	}

	for (int i = 0; i < 10; i++)
	{
    
    
		p->pa[i] = i + 1;
	}

	for (int i = 0; i < 10; i++)
	{
    
    
		printf("%d ", p->pa[i]);
	}

	//释放
	free(p->pa);
	p->pa = NULL;

	free(p);
	p = NULL;

	return 0;
}

4. Get the benefits of using flexible arrays by comparing Code 1 and Code 2

(1) The use of flexible arrays can facilitate the release of memory
incode oneWe only apply for space once and release space once . andcode twoIn the process, we apply for the space twice and release the space twice . When applying, we needFirstApply space to the structure,AgainApply for space for the pointers in the structure members, and when releasingFirstRelease the pointer application space in the structure member,AgainFree the space allocated for the structure. If the user does not know that the program first releases the space requested by the structure, then no one knows the location of the space requested by the pointer in the member of the structure and cannot be released.
(2) It can reduce memory fragmentation and speed up access (but not much).

end

If you have any suggestions and questions, or if there are any mistakes, I hope everyone can mention them.
I hope everyone can make progress with me in the future! !
If this article is useful to you, I hope you can give me a little like!

Guess you like

Origin blog.csdn.net/qq_55401402/article/details/129966469