"Volume C Record" Condensation Chapter - The Four Brothers of Dynamic Memory Management in the First Battle

In ancient times, there was no one, and Gubiao Lingyundao was a friend. The sword is my life, and it is both mad and chivalrous.

 

content

⭐1 . The main points of this chapter

⭐2 . Four areas of C/C++ memory

⭐3 . Dynamic memory allocation

2.1 What is dynamic memory allocation

2.2 Why there is dynamic memory allocation

⭐4 . Dynamic memory allocation function

4.1malloc

 4.2free

4.3calloc

4.4realloc

⭐5 . Common dynamic memory errors

5.1 Dereferencing a NULL pointer

5.2 Out-of-bounds access to dynamically developed spaces

5.3 Using free for non-dynamic memory

5.4 Use free to release part of a dynamically allocated memory

5.5 Release the same piece of dynamic memory multiple times

5.6 Dynamically open up memory and forget to release (memory leak)

⭐6 . Classic written test questions

6.1 Topic 1

6.2 Topic 2

6.3 Topic 3

6.4 Topic 4


⭐1. The main points of this chapter

  1. Introducing the four areas of C/C++ memory
  2. What is dynamic memory allocation
  3. Why dynamic memory allocation exists
  4. Four brothers of dynamic memory function: malloc, calloc, realloc, free
  5. Summarize common dynamic memory errors
  6. Analysis of Several Classic Written Exam Questions

⭐2. Four areas of C/C++ memory

As we all know, the memory is used to store the data when the program is running. In order to facilitate the management of these data, the memory is divided into four areas, namely the stack area , the heap area , the data segment , and the code segment .

 stack area:

Stack area (stack): When executing a function, the storage units of local variables in the function can be created on the stack, and the function executes
These storage units are automatically released at the end. The stack memory allocation operation is built into the instruction set of the processor, which is very efficient, but
Is the allocated memory capacity is limited. The stack area mainly stores local variables, function parameters, return data,
return address, etc.
Stack area features:
Generally, the life cycle and scope of stack variables are short, and only exist in the function stack frame (function body). When the function stack frame is destroyed (the function returns), the space to which the variable belongs is also destroyed. Therefore, the function generally does not return the address of its local variable, because that space is destroyed when the function returns, and accessing it again is an illegal access to the memory.
(Note: The function stack frame is a space specially opened up by the function in the stack area.)

Heap area:

This area is allocated and released by the programmer himself. If the allocated space is not released, it will be released by the operating system at the end of the program.

Heap area features:

 The space is allocated and released by the programmer. The data in the heap area can only be released by the programmer or the operating system when the program ends. Therefore, for some data that you want to save for a longer time, it is generally placed in the heap area, and the capacity of the heap area is larger than that of the stack. The area is bigger.

Data segment:

The data segment (static area) (static) stores global variables and static data. Released by the system after the program ends.

Data segment features:

Store global variables and static variables, also known as the global area/static area. The life cycle and scope of global variables are generally the entire program. A static variable is a variable modified by static. When a local variable is modified by static, it is placed in the data segment. At this time, its life cycle becomes longer, but the scope remains unchanged. Static Modifying the global variable will limit the scope of the global variable. At this time, its scope becomes the current file, but the life cycle remains unchanged.

Code snippet:

Code segment: Binary code that stores read-only constants/function bodies (class member functions and global functions).

Code snippet features:

The binary code of the function body is stored, and some character constants are also stored. This area is close to the area of ​​the data segment.

Summarize:

Regarding the four areas of memory, it is enough to understand these at this stage. It is not necessary to go too deep. It is just to facilitate our understanding and learning. The real memory distribution is not like this.

⭐3. Dynamic memory allocation

2.1 What is dynamic memory allocation

Baidu Encyclopedia : The so-called dynamic memory allocation (Dynamic Memory Allocation) refers to the method of dynamically allocating or reclaiming storage space in the process of program execution. Dynamic memory allocation does not require pre-allocation of storage space like arrays and other static memory allocation methods, but is allocated by the system in real time according to the needs of the program, and the size of the allocation is the size required by the program.

2.2 Why there is dynamic memory allocation

Because sometimes we need to dynamically increase our space capacity. For example, when we write an address book, we apply for 100 consecutive spaces in the stack area, then this space cannot be expanded or reduced, so it is also called static memory. Allocation, and dynamic memory allocation can just solve this problem, we can first apply for 10 spaces in the heap area, and then when the detection function checks that the space is full, then the capacity will be automatically increased. The so-called dynamic memory means that the memory of this application can be expanded or reduced, so this feature is usually used in the aspect of linked lists.

⭐4. Dynamic memory allocation function

4.1malloc

Function prototype:
void* malloc ( size_t size );
This function requests a contiguous free space from the heap and returns a pointer to this space.
  • If the opening is successful, a pointer to the opened space is returned.
  • If the development 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 space to be opened, and the user decides is used.
  • If the parameter size is 0, the behavior of malloc is undefined by the standard and depends on the compiler

 4.2free

The C language provides another function free, which is specially used for the release and recovery of dynamic memory. The function prototype is as follows:

Function prototype:

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 allocated, 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.  

for example:

#include <stdio.h>
int main()
{
	int* ptr = NULL;
	ptr = (int*)malloc(10 * sizeof(int));
	if (NULL != ptr)//判断ptr指针是否为空
	{
		//将堆区开辟的10个整形数据都置为0
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(ptr + i) = 0;
		}
	}
	free(ptr);//释放ptr所指向的动态内存
	ptr = NULL;//是否有必要?
	return 0;
}

When free (ptr), it is recommended to set ptr to NULL, otherwise ptr is a wild pointer, and there is a hidden risk.

4.3calloc

The C language also provides a function called calloc , which is also used for dynamic memory allocation.
Function prototype:
void* calloc ( size_t num , size_t size );
  •  The function of the function is to open up a space for num elements of size 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.

4.4realloc

Function prototype:

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

  • ptr is the memory address to adjust
  • new size after size 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.
  • The emergence of the realloc function makes dynamic memory management more flexible.
  • Sometimes we find that the space applied for in the past is too small, and sometimes we feel that the space applied for is too large. In order to use the memory reasonably, we must flexibly adjust the size of the memory. The realloc function can adjust the size of the dynamically allocated memory.

There are two situations in which realloc adjusts the memory space:

1. In-situ expansion

Add space directly from the back of the memory, the original data does not change.

Diagram:

 

2. Remote expansion

Because the space to be added later is too large, the heap area is not enough to continue to open up space (the space may be occupied by other variables later), so we can only find a new large memory space, copy the original data to the new space after finding it, and return The starting address of the new space.

Diagram:

 

⭐5. Common dynamic memory errors

5.1 Dereferencing a NULL pointer

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

 After opening up the heap space, check whether the return value is empty, otherwise it may fail to open up, and returning NULL will cause the subsequent null pointer dereference problem.

5.2 Out-of-bounds access to dynamically developed 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);
}

 *(p + i) = i;//Out-of-bounds access when i is 10

5.3 Using free for non-dynamic memory

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

Here a is a variable in the heap area, which does not belong to the memory opened up by the heap area, and cannot be released using free, otherwise an error will be reported. 

5.4 Use free to release part of a dynamically allocated memory

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

A piece of space opened up is either not released or all of it is released, not only a part of it

5.5 Release the same piece of dynamic memory multiple times

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

This general problem of deep copy and shallow copy in C++ is the repeated release of heap memory, which will report an error. 

5.6 Dynamically open up memory and forget to release (memory leak)

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

After using the heap memory, be sure to release the space, otherwise it will lead to memory leakage, which is a very serious matter. In the company, this is an accident, and the year-end bonus may be cancelled. Some people may say: After the program runs, won't the operating system automatically reclaim the heap space? But what if that program runs 24 hours a day? This is a very serious thing.

⭐6. Classic written test questions

6.1 Topic 1

void GetMemory(char* p) {
	p = (char*)malloc(100);
}
void Test(void) {
	char* str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}
What is the result of running the Test function?
analyze:
  • Will not print hello world, because GetMemory(str) will not change str, and str is still NULL, so when calling strcpy(), there will be a NULL dereference problem. For this, you need to know the simulation implementation of strcpy, specifically You can refer to my previous article.
  • Since the space requested by the heap area is not released, a memory leak will occur.

6.2 Topic 2

char* GetMemory(void) {
	char p[] = "hello world";
	return p;
}
void Test(void) {
	char* str = NULL;
	str = GetMemory();
	printf(str);
}

analyze:

  • Will print hello world, after str=GetMemory(), str points to the space where "hello world" is stored.
  • What needs to be parsed here is that the first address of the string passed by "hello world" is given to p, and the string is a string constant, which is usually placed in the character constant area of ​​the memory.
  • However, if the space in the heap area is not released, there will be a memory leak.

6.3 Topic 3

void GetMemory(char** p, int num) {
	*p = (char*)malloc(num);
}
void Test(void) {
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
}

analyze:

  • Will print hello, where GetMeory() passes the address of str, the address of the secondary pointer, *p is str itself, and then str points to the 100-character space of the heap area. Through the strcpy() function, hello can be copied to the heap space pointed to by str.
  • The knowledge of secondary pointers and the implementation principle of strcpy are required here. For these, you can see my previous article, where there is a very clear analysis.
  • Likewise, without free(str), there will be memory leaks.

6.4 Topic 4

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

analyze:

  • World will not be printed, str points to the 100-character space of the heap area, strcpy(str, "hello"), the heap space is put into "hello", free(str), the heap space is released, and str still points to this time In that heap space, str is a wild pointer, which is very dangerous.
  • The next if judgment statement, str is not equal to NULL, execute the conditional statement, and then copy "world" to the heap space, but because the heap space is released in advance, there will be a conflict of memory read and write access.
  • This shows that when free(str), str=NULL is very necessary.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=324036821&siteId=291194637