[advanced C language] dynamic memory management / allocation

catalogue

1, Why is there dynamic memory management / allocation?

        Storage form division of memory

2, Introduction to dynamic memory functions

        malloc

        free

        Practical application of malloc and free

        calloc

        realloc

3, Common dynamic memory errors

        Dereference operation on NULL pointer

        Cross border access to dynamically opened space

        Use free release for non dynamic memory

        Use free to release a part of dynamic memory

        Multiple releases of the same dynamic memory

        Dynamic memory forgetting to release (leading to memory leakage)

4, Memory development of C/C + + programs

5, Flexible array

        Characteristics of flexible array

        Use of flexible arrays

        Advantages of flexible arrays

1, Why is there dynamic memory management / allocation?

(1) Because memory is too valuable.

(2) If all static memory cannot be released, small programs can run completely. However, for large programs, memory will be occupied before running, and memory leakage will occur.

(3) Suppose you give a variable that takes up a variable size of memory (assuming the length len of the array), after dynamically allocating memory to the variable through the function, the size of the allocated memory is determined according to the length len of the array. Assuming that the size of len entered by the user is 5, the system will dynamically allocate memory with a length of 5 to the array. After the code runs, the system calls the free() function to release the allocated memory, Then run the rest of the program.

In other words, dynamically allocating memory can apply for memory as needed, and return it when it is used up, so that the required programs can use it.

Let's start with an example:

int a = 20;        //Local variables open up four bytes on the stack
char ch[10] = {0}; //Local variables open up 10 bytes of continuous space in the stack space
int g_a = 10;      //The global variable opens up ten bytes on the static area

The above way of opening up space has two characteristics:

  1. The size of the space is fixed.
  2. When declaring an array, you must specify the length of the array, and the memory it needs will be 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 of opening up space during array compilation can not be satisfied. At this time, you can only try dynamic storage development.  

Storage form division of memory

 

2, Introduction to dynamic memory functions

   malloc

  • Functions dedicated to dynamic memory development
//Function prototype
void *malloc (size_t size);
//void * indicates any type of pointer
//size_t means unsigned int
//size indicates that the space to be opened is in bytes

This function requests a continuously available space from memory and returns a pointer to this space.

  • If the development is successful, a pointer to the developed 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 open space, which is determined by the user when using it.
  • If the parameter size is 0, malloc's behavior is standard and undefined, depending on the compiler.

   free

  • It is a function specially used for dynamic memory release and recycling
//Function prototype
void free(void *ptr);
//void *prt indicates the type of pointer to be released

The free function is used to free dynamic memory.

  • If the space pointed to by the parameter ptr is not dynamically opened up, the behavior of the free function is undefined.
  • If the parameter ptr is a NULL pointer, the function does nothing.

Practical application of malloc and free

The code is as follows:

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

int main()
{
	//1. Apply for 10 int type spaces through dynamic development
	//Cast the type to the desired type according to the actual use
	int *p = (int*)malloc(10 * sizeof(int));
	//2.malloc may fail to apply for space, so it needs to be judged
	if (p == NULL)//Determine whether the p pointer is null
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		//Normal use space
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(p + i) = i;
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	//When the dynamically requested space is no longer used, it should be returned to the operating system
	free(p);//Free the dynamic memory pointed to by p
	p = NULL;//Is it necessary
	return 0;
}

Execution results:

reflection:

p = NULL; Is it necessary to add?

answer:

Since it will not be set as a null pointer after free, we need to manually change it into a null pointer, so p = NULL is necessary.

   calloc

  • A function that enables dynamic allocation to initialize while applying for space
//Function prototype
void *calloc(size_t num, size_t size);
//
  • The function is to open up a space for num elements with a size of {size, and initialize each byte of the space to} 0.
  • The only difference between calloc and malloc is that calloc initializes each byte of the requested space to all zeros before returning the address.

Example:

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

int main()
{
	int *p = (int*)calloc(10, sizeof(int));
	if(p == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		int i = 0;
		for(i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	//The free function is used to free up dynamically opened space
	free(p);
	p = NULL;
	return 0;
}

Execution results:

 

Summary: so how can we initialize the contents of the applied memory space? Then we can easily use the calloc function to complete the task. The calloc function initializes all the requested memory space to 0, which means that calloc runs longer than malloc. Therefore, you can choose whether to initialize these two functions.

   realloc

  • Functions that can flexibly allocate dynamic memory
  • 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 make the memory reasonable, we will flexibly adjust the size of the memory. The realloc function can adjust the size of dynamic memory.
//Function prototype
void *realloc(void *ptr, size_t size);
//void *ptr indicates the address pointed to by the adjusted pointer
//size_t size indicates the size of the memory space after the change, in bytes
  • ptr is the memory address to be adjusted
  • The return value of the new size after size adjustment is the starting position of the adjusted memory
  • This function will also move the data in the original memory to a new space on the basis of adjusting the size of the original memory space
  • realloc adjusts memory space in two ways:
  • Case 1: there is enough space behind the original space
  • Case 2: there is not enough space after the original space

Illustration:

  

Example:

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

int main()
{
	int *p =(int*)malloc(20);
	if(p == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		int i = 0;
		for(i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	//The above is only 20 bytes of space opened up by malloc
	//Suppose here, 20 bytes of space can't meet our needs

	//I hope there is 40 bytes of space
	//Here you can use realloc to adjust the dynamically opened memory
	int *ptr = realloc(p, INT_MAX);
	if(ptr != NULL)
	{
		int i = 0;
		for(i = 5; i < 10; i++)
		{
			*(p+i) = i;
		}
		for(i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	//Free dynamic memory space
	free(p);
	p = NULL;
	return 0;
}

Precautions for realloc function:

1. If the space pointed to by p has enough memory space to append, append directly and then return to p

2. If there is not enough memory space to add after the space pointed to by p, the realloc function will find a new memory area again, open up a space that meets the requirements, copy the data in the original memory back, release the old memory space, and finally return the newly opened memory space address, and the old memory space needs to be assigned a null pointer, Otherwise, a wild pointer will be formed, resulting in illegal access.

3. You have to use a new variable to receive the return value of the realloc function

Note: the above four function header files all use stdlib H header file!

3, Common dynamic memory errors

  • Dereference operation on NULL pointer

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

int main()
{
	int *p = (int*)malloc(40);
	//In case malloc fails, p will be assigned NULL
	//*p = 0;//error
	int i = 0;
	for(i = 0; i < 10; i++)
	{
		*(p+i) = i;//Illegal access
	}

	free(p);
	p = NULL;
	return 0;
}
  • Cross border access to dynamically opened space

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

int main()
{
	int *p = (int*)malloc(5 * sizeof(int));//Only 5 elements
	if( p == NULL)
	{
		return 0;
	}
	else
	{
		int i = 0;
		for(i = 0; i < 10; i++)//There are only 5 elements, and 10 cycles will cause cross-border access
		{
			*(p+i) = i;
		}
	}

	free(p);
	p = NULL;
	return 0;
}
  • Use free release for non dynamic memory

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

int main()
{
	int a = 10;
	int *p = &a;
	*p = 20;

	free(p);
	p = NULL;
	return 0;
}
  • Use free to release a part of dynamic memory

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

int main()
{
	int *p = (int*)malloc(40);
	if(p = NULL)
	{
		return 0;
	}
	int i = 0;
	for(i = 0; i < 10; i++)
	{
		*p++ = i;
	}
	//At this time, p does not point to the starting position of dynamic development
	

	//To reclaim space, free can only release the starting position opened dynamically
	free(p);
	p = NULL;
	return 0;
}
  • Multiple releases of the same dynamic memory

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

int main()
{
	int *p = (int*)malloc(40);
	if(p == NULL)
	{
		return 0;
	}

	//use
	free(p);
	//p = NULL needs to be defined as a null pointer to reference the following free
	free(p);//Repeated release
    return 0;
}
  • Dynamic memory forgetting to release (leading to memory leakage)

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

int main()
{
	while(1)
	{
		malloc(1);//After opening up the space, it has not been released
	}
	return 0;
}

Note: forgetting to release the dynamically opened space that is no longer used will cause memory leakage. The dynamically opened space must be released and released correctly

4, Memory development of C/C + + programs

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

  1. Stack area (stack): when executing a function, the storage units of local variables in the function can be created on the stack, and these storage units are automatically released when the function is executed. The stack memory allocation operation is built into the instruction set of the processor, which is very efficient, but the allocated memory capacity is limited. The stack area mainly stores the local variables, function parameters and return data allocated for running the function , return address, etc.
  2. heap: it is usually allocated and released by the programmer. If the programmer does not release it, it may be recycled by the OS at the end of the program. The allocation method is similar to the linked list.
  3. Data segment (static area): it stores global variables and static data. It is released by the system after the program is completed.
  4. Code snippet: the binary code that holds the function body (class member function and global function).

 

5, Flexible array

Perhaps you have never heard of the concept of flexible array, but it does exist. In C99, the last element in the structure is allowed to be an array of unknown size, which is called "flexible array" member.

Example:

typedef struct S
{
	int n;
	int arr[0];//Unknown size - flexible array members - the size of the array can be adjusted
    //int arr [] ditto
}S;

Characteristics of flexible array

  • A flexible array member in a structure must be preceded by at least one other member.
  • The size of this structure returned by sizeof does not include the memory of the flexible array.
  • The structure containing flexible array members uses malloc() function to dynamically allocate memory, and the allocated memory should be larger than the size of the structure to adapt to the expected size of the flexible array.

Example:

#include <stdio.h>
typedef struct S
{
	int n;
	int arr[0];//Unknown size - flexible array members - the size of the array can be adjusted
}S;

int main()
{
	struct S s;
	printf("%d\n", sizeof(s));
	return 0;
}

Execution results:

Use of flexible arrays

Example:

#include <stdio.h>
#include <stdlib.h>
typedef struct S
{
	int n;
	int arr[0];//Unknown size - flexible array members - the size of the array can be adjusted
}S;

int main()
{
	struct S *ps = (struct S*)malloc(sizeof(struct S)+5*sizeof(int));
	ps->n = 100;
	int i = 0;
	for(i = 0; i <5; i++)
	{
		ps->arr[i] = i;//0 1 2 3 4 
	}

	struct S *ptr = realloc(ps, 44);
	if(ptr != NULL)
	{
		ps = ptr;
	}
	for(i = 5; i < 10; i++)
	{
		ps->arr[i] = i;
	}
	for(i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	free(ps);
	ps = NULL;
	return 0;
}

Execution results:

Illustration:

Advantages of flexible arrays

Let's take a look at the advantages of this code over the previous code

Advantage 1: memory release

  • If our code is in a function for others, you make a secondary memory allocation in it and return the whole structure to the user.
  • The user can release the structure by calling free, but the user does not know that the members in the structure also need free, so you can't expect the user to find it.
  • Therefore, if we allocate the memory of the structure and the memory required by its members at one time and return a structure pointer to the user, the user can free all the memory once.

Advantage 2: This is conducive to access speed

  • Continuous memory is beneficial to improve access speed and reduce memory fragmentation. (in fact, I personally don't think it's much higher. Anyway, you can't run. You need to add the offset to address it.)

Keywords: C Algorithm

Added by habuchas on Wed, 15 Dec 2021 00:35:56 +0200