Memories of C (5) – Dynamic Memory Management

In this chapter, we will learn about the dynamic management of memory in C language.

Table of Contents

1. Why does dynamic memory allocation exist?

2. Introduction to dynamic memory functions

2.1 malloc and free

2.2 calloc

2.3 realloc

3. Common dynamic memory errors

3.1 Dereference operation of NULL pointer

3.2 Out-of-bounds access to dynamically opened space

3.3 Use free release for non-dynamically allocated memory

3.4 Use free to release a part of dynamically allocated memory

3.5 Release the same dynamic memory multiple times

3.6 Dynamically allocated memory and forgets to release it (memory leak)

4. Memory allocation for C/C++ programs

5. Flexible array

4.1 Characteristics of flexible arrays:

4.2 Use of flexible arrays

4.3 Advantages of flexible arrays


1. Why does dynamic memory allocation exist

The common memory allocation methods we have mastered are:

int val = 20;//Allocate four bytes on the stack space
char arr[10] = {0};//Open up 10 bytes of continuous space on the stack space

But the above-mentioned way of opening up space has two characteristics:

1. The size of the space is fixed.

2. When declaring an array, the length of the array must be specified, and the memory it requires is allocated at compile time.

But the demand for space is not just the above-mentioned situations. Sometimes we can only know the amount of space we need when the program is running, so the method of creating space during compilation of the array is not sufficient. At this time, you can only try dynamic memory allocation.

2. Introduction to dynamic memory functions

2.1 mallocandfree< /strong>

C
The language provides a dynamic memory allocation function:

void* malloc (size_t size);

This function applies for a block of memory
Continuously available
space and returns a pointer to this space.

(1) If the opening is successful, a pointer to the opened space is returned.

(2) If the development fails, return a NULL
pointer, therefore
malloc
The return value must be checked.

(3) The type of return value is void*
,so
The malloc function does not know the type of space to be opened, and the user decides by himself when using it.

(4) If parameter size
for
0
,
malloc
The behavior is undefined by the standard and depends on compilation

C language provides another function
free
, specially used to release and recycle dynamic memory
. The function prototype is as follows:

void free (void* ptr);

(1)free
Function is used to release dynamically allocated memory.

(2) If the parameter
ptr
The pointed space is not dynamically opened, then
free
The behavior of the function is undefined.

(3) If the parameter
ptr
yes
NULL
pointer, the function does nothing.

(4) malloc
and
free
are stated in
stdlib.h
in header file

Use Cases:

#include <stdio.h>
int main()
{
     //Code 1
     int num = 0;
     scanf("%d", & amp;num);
     int arr[num] = {0};
     //Code 2
     int* ptr = NULL;
     ptr = (int*)malloc(num*sizeof(int));
     if(NULL != ptr)//Determine whether the ptr pointer is empty
     {
         int i = 0;
         for(i=0; i<num; i + + )
         {
             *(ptr + i) = 0;
         }
     }
     free(ptr);//Release the dynamic memory pointed to by ptr
     ptr = NULL;//Is it necessary?
     return 0;
}

2.2 calloc

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

void* calloc (size_t num, size_t size);

(1) The function of the function is
num
size is
size
The elements open up a space and initialize each byte of the space as
0
.

(2) with function
malloc
The only difference is that
calloc
Each byte of the requested space will be initialized to the full value before returning the address.
0
.

for example:

#include <stdio.h>
#include <stdlib.h>
int main()
{
     int *p = (int*)calloc(10, sizeof(int));
     if(NULL != p)
     {
     //use space
     }
     free(p);
     p = NULL;
     return 0;
}

So if we require initialization of the contents of the applied memory space, it can be used very conveniently.
calloc
function to complete the task.

2.3 realloc

realloc
The emergence of functions makes dynamic memory management more flexible.

Sometimes we find that the space we applied for is too small, and sometimes we feel that the space applied for is too large. In order to have a reasonable amount of memory, we will definitely The memory size can be flexibly adjusted. That realloc
function can adjust the dynamically allocated memory size (
Big or small
).

The function prototype is as follows:

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

(1)ptr
is the memory address to be adjusted

(2) size
New size after adjustment

(3) The return value is the starting position of the memory after adjustment.

(4) This function not only adjusts the size of the original memory space, but also moves the data in the original memory to
new
Space.

(5) When size is zero and the pointer is NULL, that is, when the space is not allocated, realloc will perform the same function as malloc.

(6) There are two situations when realloc adjusts the memory space:

Case 1: There is enough space behind the original space

When it is case 1, if you want to expand the memory, just add space directly after the original memory, and the data in the original space will not change.

Case 2: There is not enough space after the original space

When it is situation 2, when there is not enough space after the original space, the expansion method is to find another continuous space of suitable size on the heap space to use. In this way, the function returns a new memory address.

Due to the above two situations, some attention should be paid to the use of realloc function.

for example:

#include <stdio.h>
int main()
{
     int *ptr = (int*)malloc(100);
     if(ptr != NULL)
     {
         //Business processing
     }
     else
     {
         exit(EXIT_FAILURE);
     }
     //expand capacity
     //Code 1
     ptr = (int*)realloc(ptr, 1000);//Is this okay? (What happens if the application fails?)
 
     //Code 2
     int*p = NULL;
     p = realloc(ptr, 1000);
     if(p != NULL)
     {
         ptr = p;
     }
     //Business processing
     free(ptr);
     return 0;
}

3. Common dynamic memory errors

3.1PairNULL< strong>Pointer dereference operation

void test()
{
     int *p = (int *)malloc(INT_MAX/4);
     *p = 20;//If the value of p is NULL, there will be a problem
     free(p);
}

3.2 Out-of-bounds access to dynamically allocated space

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;//out-of-bounds access when i is 10
     }
     free(p);
}

3.3 Use non-dynamically allocated memory freerelease

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

3.4 Use freeRelease a part of dynamically allocated memory

void test()
{
     int *p = (int *)malloc(100);
     p + + ;
     free(p);//p no longer points to the starting location of dynamic memory
}

3.5 Release the same dynamic memory multiple times

void test()
{
     int *p = (int *)malloc(100);
     free(p);
     free(p);//repeated release
}

3.6 Dynamically allocated memory and forgets to release it (memory leak)

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

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

Remember:

The dynamically opened space must be released and released correctly.
.

4. C/C + + Program memory allocation

Several areas of C/C++ program memory allocation:

1. Stack area (stack): When executing a function, the storage units of local variables within the function can be created on the stack, and these storage units are automatically released when the function ends. The stack memory allocation operation is built into the processor’s instruction set and is very efficient, but the allocated memory capacity is limited. The stack area mainly stores local variables, function parameters, return data, return addresses, etc. allocated for running functions.

2. Heap area (heap): Generally allocated and released by the programmer. If the programmer does not release it, it may be recycled by the OS when the program ends. The allocation method is similar to a linked list.

3. The data segment (static area) stores global variables and static data. It is released by the system after the program ends.

4. Code segment: stores the binary code of the function body (class member function and global function).

With this picture, we can better understand the static keyword to modify local variables.

In fact, ordinary local variables allocate space in the stack area. The characteristic of the stack area is that the variables created above are destroyed when they go out of scope. However, variables modified by static are stored in the data segment (static area). The characteristic of the data segment is that the variables created above are not destroyed until the end of the program, so the life cycle becomes longer.

5. Flexible array

Maybe you have never heard of the concept of flexible array, but it does exist.

In C99, the last element in a structure is allowed to be an array of unknown size. This is called a “flexible array” member.

For example:

typedef struct st_type
{
     int i;
     int a[];//Flexible array members (the number of members here is also written as 0 in some places, but some compilers will report an error when writing 0)
}type_a;

4.1 Characteristics of flexible arrays:

(1) The flexible array member in the structure must be preceded by at least one other member.

(2)sizeof
The size of this structure returned does not include the memory of the flex array.

(3) Structures containing flexible array members are used
malloc()
The function performs dynamic allocation of memory, and the allocated memory should be larger than the size of the structure to accommodate the expected size of the flex array.

example:

//code1
typedef struct st_type
{
     int i;
     int a[0];//Flexible array members
}type_a;
printf("%d\
", sizeof(type_a));//The output is 4

4.2 The use of flexible arrays

//Code 1
int i = 0;
type_a *p = (type_a*)malloc(sizeof(type_a) + 100*sizeof(int));
//Business processing
p->i = 100;
for(i=0; i<100; i + + )
{
     p->a[i] = i;
}
free(p);

So flexible array members
a
, which is equivalent to obtaining
100
A continuous space of integer elements.

4.3 Advantages of flexible arrays

abovementioned
type_a
The structure can also be designed as:

//Code 2
typedef struct st_type
{
     int i;
    int *p_a;
}type_a;

type_a *p = (type_a *)malloc(sizeof(type_a));
p->i = 100;
p->p_a = (int *)malloc(p->i*sizeof(int));
//Business processing

for(i=0; i<100; i + + )
{
     p->p_a[i] = i;
}
//Release space
free(p->p_a);
p->p_a = NULL;
free(p);
p = NULL;

The above code 1 and code 2 can accomplish the same function, but the implementation of method 1 has two advantages:

The first benefit is:
Convenient memory release

If our code is in a function for others to use, you make a secondary memory allocation in it and return the entire structure to the user. User calls free
The structure can be released, but the user does not know that the members in the structure are also needed
free
, so you can’t expect users to discover this. Therefore, if we allocate the memory of the structure and the memory required by its members at once, and return a structure pointer to the user, the user will make a free
All memory can be released as well.

The second benefit is:
This is beneficial to access speed
.

Contiguous memory is beneficial to improve access speed and reduce memory fragmentation. (Actually, I personally don’t think it’s much higher. Anyway, you can’t run and you have to use offset addition to address)

This chapter is over!

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. C Skill Tree Storage Management Memory Dynamic Management 192938 people are learning the system