Dynamic memory management malloc, free, calloc, realloc

Standing in the corner of a well, looking towards the stars

There is poetry in my eyes, I feel at home in the distance

Table of contents

A brief introduction to dynamic memory 

Advantages of dynamic memory 

Can control memory size

This space can be used multiple times

 Dynamic memory functions malloc, free

malloc open function

free release function

 Dynamic memory functions calloc, realloc

 calloc opens function

realloc adjustment function

 Common errors in the use of dynamic memory

1. Dereference operation of NULL pointer:

 2. Cross-border access to dynamically opened space

 3. Use free release for non-dynamically allocated memory

 4. Use free to release a part of dynamically allocated memory

 5. Release the same dynamic memory multiple times

6. Dynamically allocated memory and forget to release it (memory leak) 

 flexible array

 Definition of flexible array:

Features of flexible arrays:

Use of flexible arrays:


We usually don’t have enough memory when writing programsShould we manually expand the capacity

这样Procedure order small complete waste space, ForeverComplete spaceProcedure order large

When the program is not enabled, the space is stillnot released well

Don't worry we will solve such problems today

We will explain todayDynamic memory management


A brief introduction to dynamic memory 

Let’s first introduce why there is dynamic memory?

The two memory allocation methods we have learned are mainlystatic memory allocationas follows

Either use a variable to open up a space, or use an array to open up a continuous space

int a = 10;      //在栈空间上开辟四个字节
int a[4] = {0}   //在栈空间上开辟十六个字节
However, the above-mentioned method of opening up space for static memory has two flaws:
The size of space expansion is fixed .
When declaring an array, must specify the length of the array , once the array space is lost a> Confirmed Size Cannot adjust
The memory is only in the program It will only be destroyed after the operation is completed , Cannot be reused

If the size of space we need is only known when the program is running, then the previous method of compiling arrays to open up memory will not be satisfied, so we introduced dynamic memory 

Advantages of dynamic memory 

The advantages of dynamic memory are:

Can control memory size

We can apply for and release the memory space ourselves. If it is large, we can adjust it to a smaller size. If it is smaller, we can increase it. This way the program is more flexible.


This space can be used multiple times

The space allocated by dynamic memory can be used once it is used up, and then it can be free This applied space can be applied for by dynamic memory again. When the time comes, you can use this space again, which can also save a certain amount of space to a certain extent

 Dynamic memory functionsmalloc, free

malloc open function

void* malloc (size_t size);

This function applies for a continuous available space from memory, and returns a point to this space pointer 

mallocThe header file involved is#include<stdlib.h> 

  • size -- The size of the memory block, in bytes
  • If is successfully opened, this function returns a pointer pointing toallocated memory< /span>Therefore, the return value of malloc must be checked, NULL, return the request fails. If
  • The type of the return value of is void* , so the malloc function does not know the type of space to be opened. The user must use it when using it. Casting decision
  • If parameter size is 0, the behavior of malloc is undefined by the standard and depends on the compiler

Ourmalloc function applies for space in the heap area of ​​memory:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));
	//开辟一个10个整形字节的空间并用指针p来接收
	if (p == NULL) //判断开辟成功与否
	{
		perror("malloc");//报错信息函数,反应malloc的错误
		return 1;
	}
	//这样我们就可以使用这10个整形字节的空间了
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

 If the opened space is huge and malloc cannot provide such a large space, it will return a null pointer:

Now if we don’t want to use this space, can we give it back?

It’s like borrowing money. You can’t just borrow and not pay it back. We can use the free function to free up space 

free release function

void free (void* ptr);

The function of free is to release dynamically allocated memory

freeThe header file involved is#include<stdlib.h>

  • ptr -- The pointer points to the starting address of a memory block torelease the memory a> malloc, calloc or realloc , the memory block was previously allocated by calling
  • If the passed parameter is anull pointer, then will not perform any action
  • Because ptr releases the memory and still points to the starting address of the original space will become wild pointer. In order to avoid this situation, we need to manually set ptr is set to a null pointer

Take the code we just wrote as an example: 

Code written like this is perfect

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(10* sizeof(int));  //开辟空间
	if (p == NULL) 
	{
		perror("malloc");
		return 1;
	}
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	for (int i = 0; i < 10; i++)            //打印
	{
		printf("%d ", *(p + i));
	}
	free(p);   //释放空间
	p = NULL;  //手动置空
	return 0;
}

malloc, calloc, realloc If the applied space is not actively released, it will not be destroyed when it goes out of scope
Release method:< /span>
1.free active release

2. It will not be recycled by the operating system until the end of the program.


Note: In order to avoid memory leaks ( a memory space cannot be accessed by other content before it is released, and the consequences of accumulation of memory leaks are very serious, No matter how much memory there is, it will be occupied sooner or later) We should release it in time whennot using it


malloc技作: 

One thing to note is thatthe initialization of the malloc function is not 0

I have withdrawn the assignment loop just now. Let's see what the initialization value of malloc is.

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(10* sizeof(int));  //开辟空间
	if (p == NULL) 
	{
		perror("malloc");
		return 1;
	}
	for (int i = 0; i < 10; i++)            //打印
	{
		printf("%d ", *(p + i));
	}
	free(p);   //释放空间
	p = NULL;  //手动置空
	return 0;
}

What we display in hexadecimal form is a row like cd

Because the space allocated by malloc is not initialized, some exceptions may occur during operation. It is best to initialize it.  


 Dynamic memory functions calloc, realloc

 calloc opens function

 

void *calloc(size_t ptr, size_t size)

callocThe header file involved is#include<stdlib.h> 

Allocate the required memory space,and return a pointer to it

malloc calloc between< /span>Correction:

malloc does not set the memory to zero, while calloc sets the allocated memory to zero< /span>


  • ptr   --The number of elements to be allocated
  • size -- the size of the element
#include<stdio.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));
	}
	free(p);   //释放空间
	p = NULL;  //手动置空
	return 0;
}

The advantage of callo compared with malloc is that it initializes memory to 0, which can simplify the code in some cases

realloc adjustment function

 reallocThe header file involved is#include<stdlib.h> 

void *realloc(void *ptr, size_t size)
Sometimes we find that the space we applied for in the past was too small, and sometimes we feel that the space we applied for is too large.
In order to use the memory reasonably, we will definitely make flexible adjustments to the size of the memory.
The realloc function can adjust the dynamically allocated memory size

Function: Try to re-adjust the size of the memory block pointed to by ptr allocated by malloc or calloc previously called 

  • ptr  -- the pointer points to a memory block to be reallocated, the memory block before Memory is allocated by calling malloc, calloc or realloc. If it is null pointer, then allocates a new memory block< /span> returns a pointer to it, and the function
  • size -- The new size of the memory block, in bytes. If the size is 0 and ptr points to an existing memory block, the memory block pointed to by ptr will be released and a null pointer will be returned 

realloc returns NULL directly after adjustment fails. 

When realloc successfully adjusts the memory space expands , there are two situations:
Case 1: There is a large enough space after the original space
Case 2: There is not enough space after the original space  

Case 1: There is not enough space behind the opened space. In this case, the space is expanded directly. The realloc function will find a new space in the heap area of the memory ( to meet the new space size requirements), and at the same time, it will Copy the old data to the new new space, thenrelease the old space, and at the same timeReturn the starting address of the new space  

 

Case 2: Behind the space that has been opened, has enough space, proceed directly After expanding the expanded space, directly returns the starting address of the old space  

(Remember not to use directlymalloc, calloc, realloc pointer reception, if realloc is opened The space opened before the failure will not be found ) For the sake of safety, the temporary pointer ptr is used to receive and determine whether the expansion is successful

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(10* sizeof(int));  //开辟空间
	if (p == NULL) 
	{
		perror("malloc");
		return 1;
	}
	for (int i = 0; i < 20; i++)
	{
		*(p + i) = i;
	}
	for (int i = 0; i < 20; i++)        //打印
	{
		printf("%d ", *(p + i));
	}
	//空间不够,想要扩大空间,80个字节
	int* ptr = (int*)realloc(p, 20 * sizeof(int));
	if (ptr != NULL)    //如果扩容成功,就将ptr赋值给p
	{
		p = ptr;
	}
	else
	{
		perror("realloc");
		return 1;
	}
	free(p);   //释放空间
	p = NULL;  //手动置空
	return 0;
}

Of course, realloc can also expand the capacityreduce the capacity:

 realloc can adjust the size of dynamic memory space at will

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(10 * sizeof(int));  //开辟空间
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	//空间太大,想要缩小空间,20个字节
	int* ptr = (int*)realloc(p, 5* sizeof(int));
	if (ptr != NULL)    //如果缩容成功,就将ptr赋值给p
	{
		p = ptr;
	}
	else
	{
		perror("realloc");
		return 1;
	}
	for (int i = 0; i < 5; i++)
	{
		*(p + i) = i;
	}
	for (int i = 0; i < 5; i++)        //打印
	{
		printf("%d ", *(p + i));
	}
	free(p);   //释放空间
	p = NULL;  //手动置空
	return 0;
}

In addition to adjusting the function space, realloc can alsoimplement the same function as malloc:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)realloc(NULL, 10 * sizeof(int));
	if (p == NULL) 
	{
		perror("realloc");
		return 1;
	}
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	for (int i = 0; i < 10; i++)       
	{
		printf("%d ", *(p + i));
	}
	free(p);   
	p = NULL;  
	return 0;
}

Set the space pointed to by realloc to NULL, realloc can directly open up dynamic memory space


 

 Common errors in the use of dynamic memory

1. Dereference operation on NULL pointer:

Error code description:

int* p = (int*)malloc(max*sizeof(int));
*p = 10;
free(p);

Because if the allocated memory is too large, malloc will return NULL, at this time, the compiler will report an error when dereferencing a NULL pointer


after fixing:

	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL) 
	{
		perror("malloc");
		return 1;
	}
	else
	{
		*p = 20;
	}
	free(p);
    p = NULL;   

As long as we determine whether p is empty, we can avoid this kind of situation.

 2.Out-of-bounds access to dynamically opened space

Error code description:

	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL) 
	{
		perror("malloc");
		return 1;
	}
	for (int i = 0; i <= 10; i++)
	{
		*(p + i) = i;
	}
	free(p);
	p = NULL;

I opened up 10 plastic type spaces, but had to access 11 elements, which constituted out-of-bounds access.


after fixing:

	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL) 
	{
		perror("malloc");
		return 1;
	}
	for (int i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	free(p);
	p = NULL;

As long as we are careful when writing code in the future, we can avoid this situation.

 3.Use free release for non-dynamically allocated memory

Error code description:

 int a = 10;
 int* p = (int*)malloc(10 * sizeof(int));
 if (p == NULL) 
 {
	perror("malloc");
	return 1;
 }
 int *p = &a;  //p指向的空间不再是堆区上的空间
 free(p);
 p = NULL;

Assign the a address of the static stack area to p, and the space pointed by p will not be Then there is the heap area, and free can only release the space in the heap area, which causes the program to crash


Notice:

The space in the stack area cannot be freed, otherwise an error will be reported.

 4.Use free to release a part of dynamically allocated memory

Error code description:

 int *p = (int *)malloc(10*(sizeof(int));
 if (p == NULL) 
 {
	perror("malloc");
	return 1;
 }
 p++;
 free(p);
 p = NULL;
p++ causes p to no longer point to the starting position of dynamic memory . The free function must be released from < a i=3>The starting position starts to be released, so the program crashes

Notice:

Do not arbitrarily change the position of the pointer to the dynamic memory space

 5.Release the same dynamic memory multiple times

Error code description:

	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL) 
	{
		perror("malloc");
		return 1;
	}
	free(p);
	free(p);
	p = NULL;

Release the same space multiple times Cause the program to crash


after fixing:

	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL) 
	{
		perror("malloc");
		return 1;
	}
	free(p);
    p = NULL;
    free(p);
	p = NULL;

Redefining p as a null pointer can free up space again, but it has no practical significance. Be careful not to release the same space multiple times

6. Dynamically allocated memory and forget to release it (memory leak) 

void test()
 {
 int *p = (int *)malloc(10*sizeof(int));
 if(NULL != p)
 {
 *p = 20;
 }
 }
int main()
 {
 test();
 while(1);
 }

malloc assigns 10 integer bytes of space to p, but does not release the space. p is a local variable and is destroyed when it leaves the function definition domain. Then these 10 integer bytes cannot be found and cannot be released (unless End of program). So is the space of these 10 integer bytes equal to a memory leak? Memory leaks will cause the program to occupy more and more memory, eventually leading to crash

Forgetting to release dynamically allocated space that is no longer used can cause memory leaks.

After modification:
void test()
 {
 int *p = (int *)malloc(10*sizeof(int));
 if(NULL != p)
 {
 *p = 20;
 }
 free(p);
 p = NULL;
 }
int main()
 {
 test();
 while(1);
 }

So everyone remember to release the memory after allocating it.


 flexible array

 Definition of flexible array:

 The last element in the structure is allowed to be an array of unknown size. This is called a "flexible array" member.

struct Stu
{
	int num;
	int arr[];//柔性数组的成员
};
//或者
struct Stu
{
	int num;
	int arr[0];//柔性数组的成员
};

Features of flexible arrays:

The flexible array member in the structure must be preceded by at least one other member
The size of this structure returned by sizeofdoes not include the memory of the flexible array
A structure containing flexible array membersUse the malloc () function to dynamically allocate memory, and the allocated memoryshould be larger than the size of the structureto accommodate the expected size of the flex array

 Let’s take a look at the structure size of this code below.

#include<stdio.h>
struct Stu
{
	int num;
	int arr[];
}S;
int main()
{
	printf("%d\n", sizeof(S));
	return 0;
}

We found that the size of the structure is 4, which is the size of an integer member, so the flexible array does not occupy the space of the structure.


Use of flexible arrays:

 Let’s look at the following code:

When the structure has 4 bytes, we have opened up 10 more integer bytes for the structure. So who uses these 10 integer bytes?

The answer is of course ours -Flexible array

#include<stdio.h>
#include<stdlib.h>
typedef struct
{
	int num;
	int arr[];
}Stu;
int main()
{
	int i = 0;
	Stu* p = (Stu*)malloc(sizeof(Stu) + 10 * sizeof(int));
	if (p == NULL)
	{
		perror("malloc");
		return 1;
	}
	p->num = 100;
	for (i = 0; i < 10; i++)
	{
		p->arr[i] = i;
	}
	printf("%d\n", p->num);
	for (i = 0; i < 10; i++)
	{
		printf("%d ", p->arr[i]);
	}
	free(p);
	p = NULL;
	return 0;
}

 Using a flexible array to expand a structure like this can also be done using our direct memory function:

We expand the space pointed by arr in this way, and release the space pointed by arr after use.

#include<stdio.h>
#include<stdlib.h>
typedef struct
{
	int num;
	int* arr;
}Stu;
	int main()
	{
		Stu* p = (Stu*)malloc(sizeof(Stu));
		p->num = 100;
		if (p == NULL)
		{
			perror("malloc");
			return 1;
		}
		p->arr = (int*)malloc(10 * sizeof(int));
		if (p == NULL)
		{
			perror("malloc-2");
			return 1;
		}
		printf("%d\n", p->num);
		for (int i = 0; i < 15; i++)
		{
			p->arr[i] = i;
		}
		for (int i = 0; i < 15; i++)
		{
			printf("%d ", p->arr[i]);
		}
		int* ptr = (int*)realloc(p->arr, 15 * sizeof(int));
                //如果空间不够用,进行内存扩容
		if (ptr == NULL)
		{
			perror("realloc");
		}
		else
		{
			p = ptr;
		}
		for (int i = 10; i < 15; i++)
		{
			p->arr[i] = i;
		}
		for (int i = 10; i < 15; i++)
		{
			printf("%d ", p->arr[i]);
		}
		free(p->arr); //释放的是指向arr的空间
		p->arr = NULL;
		free(p);      //释放的是p的空间
		p = NULL;
	return 0;
}

Abovecode1 andcode 2 can accomplish the same function, but the implementation of flexible array has two advantages:  

Convenient memory release:
Flexible arrayThe expansion only requiresone release, while using the second one requires Perform multiple releases
Conducive to improving access speed:
Contiguous memory is beneficial to improve access speed and also helps to reduce memory fragmentation (which will make the program memory utilization not high) a>


That’s all for this issue of dynamic memory.

I hope this knowledge will give you a deeper understanding of dynamic memory

See you next time~

Guess you like

Origin blog.csdn.net/2301_79201049/article/details/134890419