Advanced C language - dynamic memory management

Long time no see. Today we will learn about dynamic memory management in C language. This is a chapter as important as pointers, so you must study this chapter well.

1. Why does dynamic memory allocation exist?

The memory development methods we have mastered are:

int val = 20;//在栈空间上开辟四个字节
char arr[10] = {
    
    0};//在栈空间上开辟大小为十个字节大小的内存,并且他们是连续的


However, the above-mentioned way of opening up space has two characteristics;

  1. The space allocation size is fixed.
  2. When the array is declared, the length of the array must be specified, and the memory it needs is allocated at compile time.
    But the demand for space is not just the above situation. Sometimes the size of the space we need can only be known when the program is running, and
    the way to open up space when the array is compiled cannot be satisfied.
    At this time, we can only try dynamic storage to open up space.

2. Introduction to dynamic memory functions

malloc

insert image description here
void* malloc (size_t size);
Let us first understand the return value and parameters of this function

Its return value is the first address to open up the dynamic memory space. If the opening is not successful, it will return a
null pointer. The parameter is the byte size. write 40 bytes to open

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.
  • 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.
  • If the parameter size is 0, the behavior of malloc is undefined by the standard and depends on the compiler.

Similarly, we have malloc to open up space, then we can use free to release space

insert image description here

This function is to release the space we opened up with the malloc function to open up memory space, that is, they must be used consecutively, otherwise there will be a memory leak problem, so our memory will be used up bit by bit.

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.

Then let's use an example to realize how to use these two functions.
Their header file is <stdlib.h>

#include<stdio.h>
#include<stdlib.h>
int main()
{
    
    
	int arr[10] = {
    
    0};//这是在栈上开辟的空间
	int* ptr = (int*)malloc(40);//开辟十个整型
	//在内存上开辟
	if (ptr == NULL)
	{
    
    
		perror("malloc");
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 10; i++)
	{
    
    
		*(ptr + i) = i;
	}
	for (i = 0; i < 10; i++)
	{
    
    
		printf("%d ", *(ptr + i));
	}
	//使用完之后释放
	free(ptr);
	ptr = NULL;
	//我们要把它变成空指针,要不然可能就会变成野指针
	return 0;
}

When our dynamic memory is developed, it is developed in the heap area. The stack area is developed for local variables and temporary variables, which will be destroyed when they are popped out of the stack, so we don’t need to free it. There is also our static area, which stores our global data. variables and static variables.

Let me give you an example to illustrate the importance of free. This example will help you understand better
. , they broke up (free), but the male student is obsessed with it. He is a licking dog. He still remembers the female classmate’s phone number and harass the female classmate from time to time. Address) hit him in the head, let it down, and forget this phone number, then he can't harass other female classmates.

calloc

insert image description here
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 first parameter in the function is to open up several elements, and the second parameter is the size of each element. In fact, it is similar to malloc, but when we use calloc, the content we open will be initialized to 0.

#include<stdio.h>
#include<stdlib.h>
int main()
{
    
    
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
    
    
		perror("CALLOC");
		return 1;
	}
	free(p);
	p = NULL;
	return 0;
}

insert image description here

  • 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.
#include<stdio.h>
#include<stdlib.h>
int main()
{
    
    
	int* p = (int*)calloc(10, sizeof(int));
	if (p == NULL)
	{
    
    
		perror("Calloc");
		return 1;
	}
	int i = 0;
	
	for (i = 0; i < 10; i++)
	{
    
    
		printf("%d ", *(p+i));
	}
	free(p);
	p = NULL;
	return 0;
}

insert image description here
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 applied for is too large. In order to make the memory reasonable, we must make flexible adjustments to the size of the memory. Then the realloc function can adjust the size of the dynamically allocated memory

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

insert image description here

ptr is the memory address
size to be adjusted, the new size after adjustment,
and the return value is the starting position of the memory after adjustment.
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.

But when our development is unsuccessful, the return value will be different from the above two different situations

  • Case 1: There is enough space after the original space
  • Case 2: There is not enough space after the original space
  • Case 3: return a null pointer, this is not successfully opened

Here we mainly talk about situation 2, because realloc is to increase memory space, for example, our malloc opens up ten integers, but now we need 20, then we can write it as, but there will be problems when opening, (int*)realloc(p,80)if there is not enough space behind , he cannot be opened, then we need to find a new location to open, and continue to look for a location in the heap area to open. At this time, the address we return is not the original one, but a new address.

insert image description here

Then let's look at the code to see how he uses it


#include<stdio.h>
#include<stdlib.h>
int main()
{
    
    
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
    
    
		perror("Malloc");
		return 1;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
    
    
		*(p + i) = i;
	}
	
	int* tmp = (int*)realloc(p, 80);
	if (tmp == NULL)
	{
    
    
		perror("Realloc");
		return 1;
	}
	else
	{
    
    
		p = tmp;
	}
	for (i = 0; i < 20; i++)
	{
    
    
		*(p + i) = i;
	}
	for (i = 0; i < 20; i++)
	{
    
    
		printf("%d ", p[i]);
	}
	free(p);
	p = NULL;
	free(tmp);
	p = NULL;
	return 0;
}

3.1 Dereference operation on NULL pointer

void test()
{
    
    
 int *p = (int *)malloc(INT_MAX/4);
 *p = 20;//如果p的值是NULL,就会有问题
 free(p);
}

For example, here we have to judge p to see if it is a null pointer. If it is a null pointer, there will be a problem, which is an illegal access.

Solution: make a non-null judgment on p

3.2 Out-of-bounds access to dynamically allocated spaces

void test()
{
    
    
 int i = 0;
 int *p = (int *)malloc(10*sizeof(int));
 if(NULL == p)
 {
    
    
    return 1;
 }
 for(i=0; i<=10; i++)
 {
    
    
 *(p+i) = i;//当i是10的时候越界访问
 }
 free(p);
}

So we have to judge whether our access range is out of bounds after writing

3.3 Use free to release non-dynamic memory

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

We developed this on the stack, we don't need to release it, the operating system will automatically destroy it

3.4 Use free to release part of a dynamically allocated memory

void test()
{
    
    
 int *p = (int *)malloc(100);
 p++;
 free(p);//p不再指向动态内存的起始位置
}

This type of problem is very common. If we change the initial position, we cannot completely release it, so we must release it from the initial position we created this dynamic memory. 3.5 Multiple releases
of the same dynamic memory

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

So we have to change it to a null pointer after each release

3.6 Dynamically open up memory and forget to release it (memory leak)

We forget to release when we finish writing the code, which will lead to memory leaks

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

Solution, free (release) and set to a null pointer

That’s all for today’s sharing. In the next issue, we will share a few written test questions

Guess you like

Origin blog.csdn.net/2301_76895050/article/details/131867050