C language dynamic memory management (1)

The main content of this article;
1. Why is there dynamic memory allocation?
2. Introduction to dynamic memory functions
✨malloc
✨free
✨calloc
✨realloc
3. Common dynamic memory errors
4. Several classic written test questions
5. Flexible arrays

1. Why is there dynamic memory allocation?

The memory allocation methods we have mastered include:
creating a variable or creating an array,
but the above method of opening up space has two characteristics:
1. The size of the space allocation 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

In fact, for space requirements, sometimes the size of the space we need can only be known when the program is running, so the above method of creating an array cannot be satisfied.
Then you need to use dynamic memory development.

2. Introduction to dynamic memory functions

1.malloc

The malloc header file <stdlib.h>
C language provides a dynamic memory opening function.
insert image description here
This function applies for a continuous available space from the memory and returns a pointer to this space .
(1) If the allocation is successful, return a pointer to the allocated space.
(2) If the development fails, a NULL pointer is returned, so the return value of malloc must be checked . (Note that the development fails because malloc will not continue to develop without restraint)

Judge the return value of malloc:
if(p= =Null){
printf(“%s\n”,strerror(errno));
return 1;
}else{

}

Note:
a. strerror(errno): return the string address of the error message corresponding to the error code
b. strerror header file <string.h>
c. errno header file <errno.h>

(3) 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.
(4) If the parameter size is 0, the behavior of malloc is undefined by the standard and depends on the compiler.
(5) The use of malloc:

//malloc的使用
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
int main() {
    
    
	//张三
	//申请
	int* p = (int*)malloc(20);
	//对malloc的返回值进行判断
	if (p == NULL) {
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 5; i++) {
    
    
		p[i] = i + 1;//相当于*(p+i)=i+1;
	}
	for (i = 0; i < 5; i++) {
    
    
		printf("%d ", p[i]);
	}
	//释放malloc开辟的空间并置空
	free(p);
	p = NULL;
	return 0;

}

insert image description here
(6) The heap initializes the space from malloc by default.
If you do not put a value in the malloc space, the value of the directly printed space is some random value

//堆默认给malloc出来的空间初始化
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
int main() {
    
    
	//张三
	//申请
	int* p = (int*)malloc(20);
	//对malloc的返回值进行判断
	if (p == NULL) {
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	//直接打印
	int i = 0;
	for (i = 0; i < 5; i++) {
    
    
		printf("%d ", p[i]);
	}
	//释放malloc开辟的空间并置空
	free(p);
	p = NULL;
	return 0;

}

insert image description here

2.free

The free header file <stdlib.h>
is specially used for the release and recovery of dynamic memory. The function prototype is as follows: The
insert image description here
free function is used to release the dynamically opened memory:
(1) The starting address of the space to be released is passed to free
(2) ptr must point to the dynamically opened space before it can be released by free (
3) Free is a null pointer, and nothing will be done
(4) Before free, the pointer ptr originally points to a place. An address is stored, if it is not empty, this address will be used by people with ulterior motives, ptr is a wild pointer.
So: After releasing the pointer, set the pointer to a null pointer actively, so that the space just opened can no longer be found, and wild pointers are avoided

3.calloc

The calloc function is also used for dynamic memory allocation. The prototype is as follows:
insert image description here
callloc(num elements, the byte size of each element)
calloc will open up a memory block like an array
Notes:
(1) The function of calloc is to open up a space for num elements whose size is size bytes, and initialize each byte of the space to 0. (2) The difference between calloc and malloc opening up space is that calloc will initialize each byte of the requested space to 0 before returning the address. The parameters are different b. All apply for memory space on the heap area, but malloc is not initialized, and calloc
will be initialized to 0


If you want to initialize, use calloc
If you don't need to initialize, use malloc

(4) Use calloc as an example:

//举例使用calloc
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main() {
    
    
	int* p = (int*)calloc(10, sizeof(int));
	//判断是否开辟成功
	if (p == NULL) {
    
    
		printf("%s\n", strerror(errno));
		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

4.realloc

realloc can adjust the size of the space.
The function prototype is as follows:
insert image description here
realloc (the memory address of the space to be adjusted, the new size of the adjusted space)
returns the starting position of the adjusted memory
important point
(1)realloc调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间
(2)realloc在调整内存空间时存在两种情况:
第一种情况:原有空间之后有足够大的空间,realloc后面追加的新的空间是不会赋初值的,只会把旧的数据拷贝下来,此时realloc返回的是旧地址
insert image description here
第二种情况:原有空间之后没有足够大的空间,扩展的方法是在堆空间上另找一个更大的连续空间来使用,将原来的数据拷贝到新的空间,释放旧的空间,此时函数返回一个新的内存地址
insert image description here
(3)堆中开辟的内存不一定是连续的
(4)如果realloc调整的空间要比原空间小, 多余的空间会全释放不使用,还给操作系统
(5)举例使用realloc:

//举例使用realloc:
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<stdlib.h>
int main() {
    
    
	int* p = (int*)malloc(20);
	if (p == NULL) {
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	//使用
	int i = 0;
	for (i = 0; i < 5; i++) {
    
    
		p[i] = i + 1;
	}
	int* ptr = (int*)realloc(p, 40);
	if (ptr != NULL) {
    
    
		p = ptr;
	}
	else {
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	//调整空间后使用
	for (i = 0; i < 10; i++) {
    
    
		p[i] = i + 1;
	}
	for (i = 0; i < 10; i++) {
    
    
		printf("%d ", p[i]);
	}
	//释放malloc开辟的空间
	free(p);
	p = NULL;
	return 0;
}

insert image description here

3. Common dynamic memory errors

1. Dereference operation on NULL pointer

malloc/calloc dynamic development failed, did not check the return value
Example: Analysis
insert image description here
:
If the dynamic memory allocation fails, the p pointer is a null pointer. When i=0, there is a problem with dereferencing the p pointer (null pointer), and the null pointer cannot be dereferenced.

2. Out-of-bounds access to dynamically allocated spaces

Access as many bytes as the dynamic development has applied for, and do not cross the boundary
Example:
insert image description here
Analysis:
A total of 20 bytes of integer space has been opened up, and 10 integers (40 bytes) of data have been accessed during access, out-of-bounds access

3. Use free to release non-dynamically allocated memory

If the space opened up in memory is not on the heap, it cannot be released with free
Example:
insert image description here
Analysis:
The local variables or arrays in the function are all space opened on the stack and cannot be released with free

4. Use free to release part of the dynamically allocated memory

free to release space must provide the starting position of the space to be freed
Example: Analysis
insert image description here
: The pointer to the starting position of the dynamically opened space is modified during use, and no longer points to the starting position. When the space is recovered by free after use, the starting position of the dynamically opened memory space cannot be provided, and a program error occurs.

5. Multiple releases of the same dynamic memory

(1) The space dynamically created by malloc/calloc cannot be released once it is let go. If it is set to a null pointer after the first release, the second release is equivalent to releasing the null pointer.
(2) When interacting with other functions, if you don’t know the inside of the function, it is likely that you have already released it once inside the function, and released it once again in the main function, resulting in multiple releases of the same dynamic memory error;

Example: Analysis
insert image description here
:
There is a problem with the continuous and repeated release of the same piece of dynamic memory

It is no problem to make it empty after release, and then release, as follows:
insert image description here

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

It refers to the dynamic opening of memory neither using free release nor ending the program
✨Key points✨
(1) If you do not want to use the space applied by malloc / calloc / realloc, you need to use free to release it. If it is not released, it will also be recycled by the operating system after the program ends.
(2) If you do not use free to release, the program will not end, which will cause memory leaks

It means that if you don’t need to return it, the program will not end, and others will not be able to use this space, which means that this space is wasted

(3) Two ways to reclaim memory:
a. free
b. After the program ends, it will be reclaimed by the operating system

Example:
insert image description here
Analysis:
The requested 20-byte address is placed in the p pointer, and p is a local variable. Once the function returns, p will be destroyed and disappeared, and the 20-byte address is not returned through p. So out of the function and inside the main function, the main function can’t find where this memory space is, and it can’t be released even if it wants to, causing a memory leak

Guess you like

Origin blog.csdn.net/qq_66238381/article/details/131741234