Deep understanding of dynamic memory allocation

Posted by xdracox on Fri, 29 Oct 2021 08:13:17 +0200

Introduction to dynamic memory functions

  1. malloc
  2. free
  3. calloc
  4. realloc

Why is there dynamic memory allocation

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

	However, the above-mentioned 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.
However, the demand for space is not limited to the above situations. Sometimes the size of space we need can be known when the program is running,
The way to open up space during the compilation of arrays cannot be satisfied. At this time j You can only try dynamic memory development

Introduction to dynamic memory functions

malloc

malloc open space free free space
c language provides a function of dynamic memory development
void* malloc(size_t size);
This function requests a continuously available space from memory and returns a pointer to this space.
1. If the development is successful, a pointer to the developed space will be returned
2. If the development fails, a null pointer will be returned. Therefore, the return value of malloc must be checked
3. The type of the return value is void *, so the malloc function does not know the type of open space. The user can decide the specific type of space when using it
4. If the parameter size is 0, the behavior of mallocd is standard and undefined, depending on the compiler

free

c language provides another function free, which is specially used for dynamic memory release and recovery. The function prototype is as follows
void free(void* ptr);
The free function is used to free dynamic memory
1. If the space pointed to by the parameter ptr is not dynamically opened up, the behavior of the free function is undefined.
2. If the parameter ptr is a NULL pointer, the function does nothing
malloc and free are declared in the stdlib.h header file,

calloc

c language also provides a function called calloc, which is also used for d dynamic memory allocation,
void* calloc(size_t num,size_t size);
1. The function is to open up a space for num size elements and initialize each byte of the space to 0
2. The difference from malloc is that malloc initializes each byte of the requested space to all zeros before returning the address

realloc

Therefore, how to initialize the contents of the requested memory space? It is convenient to use the calloch function to complete the task
realloc
1. The appearance of realloc function makes dynamic memory management more flexible
2. Sometimes we find that the space applied for in the past is small, and sometimes we feel that the space applied for is too large, so we have a reasonable time memory,
We will adjust the memory size flexibly. The realloc function can adjust the dynamic development memory size. The functions are as follows
void* realloc(void* ptr,size_t size);
ptr is the memory address to be adjusted
New size after resizing
The return value is the adjusted memory starting position
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
There are two situations when realloc adjusts memory space
Case 1: there is enough space after the original space
Case 2: there is not enough space after the original space

malloc usage

int main()
{
	//Request 10 shaping spaces from memory
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == 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);
	p = NULL;
	This means that the relationship is broken and the phone number is still there,
	So let the phone number go free,Let you forget the number
	return 0;
}

calloc usage

int main()
{
	//malloc(10*sizeof(int)); Here is the total size
	int* p = (int*)calloc(10, sizeof(int));
	//Here is to calculate several elements, and then the size of each element
	//calloc initializes the element to 0, but malloc does not
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));//Type out the error code and the corresponding information
	}
	else
	{
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	//Free up space
	//The free function is used to release the dynamically opened space
	free(p);
	p = NULL;
	return 0;
}

realloc

realloc Adjust the size of dynamic memory space
int main()
{
	int* p = (int*)malloc(20);
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		int i = 0;
		for (i = 0; i < 5; i++)
		{
			*(p + i) = i;
		}
	}
	Is using malloc Open up 20 bytes of space
	Suppose that 20 bytes here can't meet our use
	I hope we can have 40 bytes of space
	You can use it here realloc To adjust the dynamic memory	

	realloc Precautions for use:
	1.If p If there is enough memory space to append after the space pointed to, append directly and return p
	2.If p There is not enough memory space to append after the space pointed to realloc The function will find a new memory area again
	Open up a space to meet the needs, and copy back the data in the original memory to free up the old memory space,last
	Returns the address of the newly opened memory space
	3.You have to receive it with a new variable realloc Return value of function
	int* ptr = realloc(p,INT_MAX);
	if (ptr != NULL)
	{
		p = ptr;
		int i = 0;
		for (i = 5; i < 10; i++)
		{
			*(p + i) = i;
		}
		for (i = 0; i < 10; i++)
		{
			printf("%d ", *(p + i));
		}
	}
	//Free memory
	free(p);
	p = NULL;		
	return 0;
}

Common dynamic memory errors

The first error is dereference of NULL pointer

int main()
{
	int *p = (int*)malloc(40);
	//In case malloc fails, p is assigned NULL
	//So be sure to judge
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(p + i) = i;
		}
	}
	free(p);
	p = NULL;
	return 0;
}

Second error

Out of bounds access to dynamic memory

int main()
{
	int *p = (int*)malloc(5 * sizeof(int));//Here it opens up five integer elements
	if (p == NULL)
	{
		printf("%s\n", strerror(errno));
	}
	else
	{
		int i = 0;
		for (i = 0; i < 10; i++)//10 elements are accessed here, so cross-border access
		{
			*(p + i) = i;
		}
	}
	free(p);
	p = NULL;
	return 0;
}

The third error is the misuse of free. Free is in the heap

int main()
{
	int a = 10;
	int* p = &a;
	*p = 20;
	//Use of non dynamic memory free release
	free(p);
	p = NULL;
	return 0;
}

Fourth error

Use free to release part of dynamic memory

int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		return 0;
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*p++ = i;
	}
	//Recycle space
	free(p);//p no longer points to the beginning of dynamic memory
 The mistake here is p What is released is the space behind, not the space at the beginning
	p = NULL;
	return 0;
}

Fifth error

Multiple releases of the same dynamic memory

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

The sixth error, dynamic development, memory forgetting to release (memory leak)

int main()
{
	while (1)
	{
		malloc(1);//Free is not used to free memory
	}
	return 0;
}
Forgetting to release the dynamically opened space that is no longer used will cause memory leakage. Remember to release the dynamically opened space
 And must be released correctly

Several classic written questions

What will be the result of running the Test function

void GetMemory(char* p)
{
	p = (char *)malloc(100);
}
void Test(void)
{
	char *str = NULL;
	GetMemory(str);
	strcpy(str, "hello world");
Here, the program will crash because the memory access fails,
because str It doesn't point to effective space,
	
	Failure reason:
	1.The program running the code will crash
	2.There is a memory leak in the program
	str Pass values to p
	p yes GetMemory The formal parameters of a function can only be valid inside the function, etc GetMemory After the function returns, the dynamic memory has not been released,
	And can not be found, so it will cause memory leakage
	
	printf(str);
}
int main()
{
	Test();
	return 0;
}

Improve the above code into the correct code

Improvement method 1
void GetMemory(char** p)
{
	*p = (char *)malloc(100);
}
void Test(void)
{
	char *str = NULL;
	GetMemory(&str);
	strcpy(str, "hello world");
	printf(str);
}
int main()
{
	Test();
	return 0;
}
Improvement method II
char* GetMemory(char* p)
{
	p = (char *)malloc(100);
	return p;
}
void Test(void)
{
	char *str = NULL;
	str = GetMemory(str);
	strcpy(str, "hello world");
	printf(str);
}
int main()
{
	Test();
	return 0;
}

What will be output when the test function is executed

Structure is random value
char* GetMemory(void)
{
	char p[] = "hello world";
	//Here is a local variable, which is only valid inside the function. Its life cycle is to enter its scope, start its life cycle and leave its scope,
	//At the end of the life cycle, when you go out, you do return the address, but this space is returned to the operating system, and the values in this space are next
	//What is random
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
int main()
{
	Test();
	return 0;
}

Interview simulation questions return to stack space

int* test()
{
	//static int a = 10; Static zone
	int a = 10;//Stack area
//Just add a static in front of the stack area
//Because static modifies local variables, the life cycle of local variables becomes longer. a is not destroyed except for the scope
	return &a;
}
int main()
{
	int* p = test();
	*p = 20;
	return 0;
}
int* test()
{
	int * ptr = malloc(100);//Only free can recycle the heap space in the heap area, so it is also possible here
	return ptr;
}
int main()
{
	int* p = test();
	return 0;
}

What will be the result of running the Test function

void GetMemory(char **p, int num)
{
	*p = (char *)malloc(num);
}
void Test(void)
{
	char *str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
	free(str);
	str = NULL;
	//The print result here is hello
/*
Forget to release the dynamically opened memory, resulting in memory leakage. Use free to release it	
*/
}
int main()
{
	Test();
	return 0;
}
void Test(void)
{
	char *str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
//After free releases the space pointed to by str, it will not set str to null, so you should add str = null and set free to null after free release
	if (str != NULL)
	{
		strcpy(str, "world");
		//Illegal access to memory. You have released it, but you still want to access it
		printf(str);
	}
}
int main()
{
	Test();
	return 0;
}

Several areas of memory allocation in c/c + + programs

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


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

Flexible array

In C99, the last element in the structure is allowed to be an array of unknown size, which is called a [flexible array] member
Both methods are OK. If the compiler of the first method cannot compile, use the second method

The first method(1)If the compiler doesn't work, which of the following is used
struct S
{
	int n;
	int arr[];	//The last element in the structure is of unknown size
	Unknown size-Flexible array member -The size of the array can be adjusted
};
(2)
struct S
{
	int n;
	int arr[0];	//The last element in the structure is of unknown size
 Unknown size-Flexible array member -The size of the array can be adjusted

Specific use of flexible arrays

struct S
{
	int n;
	int arr[0];//Unknown size - flexible array members - the size of the array can be adjusted
};
int main()
{													  //Here is the space creation of flexible array
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 5*sizeof(int));
	ps->n = 100; //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);//Adjust the flexible array to become more points	
	if (ptr != NULL)
	{
		ps = ptr;
	}
	for (i = 5; i < 10; i++)
	{
		ps->arr[i] = i;
	}
	for (i = 0; i < 10; i++)//Print here
	{
		printf("%d ", ps->arr[i]);
	}
	//Free up space
	free(ps);
	ps = NULL;
	return 0;
}

Other methods

struct S
{
	int n;
	int* arr;
};
int main()
{
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	ps->arr = malloc(5 * sizeof(int));
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		ps->arr[i] = i;
	}
	for (i = 0; i < 5; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	//Resize
	int * ptr = realloc(ps->arr,10*(sizeof(int)));
	if (ptr != NULL)
	{
		ps->arr = ptr;
	}
	for (i = 5; i < 10; i++)
	{
		ps->arr[i] = i;
	}
	for (i = 0; i < 10; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	//Free memory
	free(ps->arr);
	ps->arr = NULL;
	free(ps);
	ps = NULL;
	return 0;
}

After two convenient comparisons, flexible arrays are better. malloc free uses less and has less error probability
The second method has a high error rate. The more malloc is used, the more memory fragments are used, and the memory utilization is low

Characteristics of flexible array

  1. A flexible array member in a structure must be preceded by at least one other member
  2. The size of this structure returned by. sizeof does not include the memory of the flexible array
  3. 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 accommodate the expected size of the flexible array

Advantages of flexible arrays

1. It is convenient to release the memory. You can release all the memory by making a free
2. This is conducive to access speed

Finally, a great God and its motto are introduced

Chen Hao


Topics: C