catalogue
1. Why is there dynamic memory allocation
2. Introduction to dynamic memory function
3. Common dynamic memory errors
4. Memory development of C / C + + program
1. Why is there dynamic memory allocation
Let's start with two simple examples
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 space development size is fixed.
2. When the array is declared, the length of the array must be specified, 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 space we need can only be known when the program is running,
The way to open up space during the compilation of arrays cannot be satisfied.
At this time, you can only try dynamic storage development.
2. Introduction to dynamic memory function
2.1 malloc and free
C language provides a function for dynamic memory development:
void* malloc (size_t size);
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 the open space. When using it, the user will
It's up to you.
If the parameter size is 0, malloc's behavior is standard and undefined, depending on the compiler.
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.
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.
malloc and free are both declared in the stdlib.h header file.
for instance:
#include <stdio.h> int main() { int* ptr = NULL; ptr = (int*)malloc(num*sizeof(int)); if(NULL != ptr)//Determine whether the ptr pointer is null { int i = 0; for(i=0; i<num; i++) { *(ptr+i) = 0; } } free(ptr);//Freeing the dynamic memory pointed to by ptr ptr = NULL;//Is it necessary? return 0; }
It is very important to set ptr as null pointer here, because the space after release does not belong to us. If you access it again, it will cause illegal access
2.2 calloc
C language also provides a function called calloc, which is also used for dynamic memory allocation. The prototype is as follows:
void* calloc (size_t num, size_t size);
The function is to open up a space for num size elements, 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.
for instance:
#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; }
Therefore, how to initialize the contents of the applied memory space? It is convenient to use the calloc function to complete the task.
2.3 realloc
The emergence of 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. That's for a reasonable reason
When waiting for memory, we will flexibly adjust the size of memory. Then the realloc function can make a large memory for dynamic development
Small adjustments.
The function prototype is 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.
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
Case 1
In case 1, to expand the memory, directly add space after the original memory, and the data in the original space will not change.
Case 2
In case 2, when there is not enough space after the original space, the expansion method is to find another appropriate size on the heap space
Continuous space to use. In this way, the function returns a new memory address.
Due to the above two cases, we should pay attention to the use of realloc function.
for instance:
#include <stdio.h> int main() { int *ptr = (int*)malloc(100); if(ptr != NULL) { //Business processing } else { exit(EXIT_FAILURE); } //Expansion capacity //Code 1 ptr = (int*)realloc(ptr, 1000);//Is this ok? (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; }
What we need to pay attention to is
ptr = (int*)realloc(ptr, 1000);
This method is wrong. If our memory application fails and a null pointer is returned, the original ptr will be set as a null pointer and the original position will be lost
We usually use a new pointer to receive
For example: int *p=(int*)realloc(ptr,1000);
3. Common dynamic memory errors
3.1 dereference of NULL pointer
void test() { int *p = (int *)malloc(INT_MAX/4); *p = 20;//If the value of p is NULL, there is a problem free(p); }
3.2 cross border access to dynamic development 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;//Cross border access when i is 10 } free(p); }
3.3 use free release for non dynamic memory
void test() { int a = 10; int *p = &a; free(p);//ok? }
3.4 use free to release a part of dynamic memory
void test() { int *p = (int *)malloc(100); p++; free(p);//p no longer points to the beginning of dynamic memory }
It can't be released here.
3.5 multiple releases of the same dynamic memory
void test() { int *p = (int *)malloc(100); free(p); free(p);//Repeated release }
This is also wrong.
We'd better empty the memory at the same time after each release, so as to reduce errors
free(p);
p=NULL;
3.6 dynamic memory forgetting to release (memory leakage)
void test() { int *p = (int *)malloc(100); if(NULL != p) { *p = 20; } } int main() { test(); while(1); }
Forgetting to free dynamic space that is no longer in use can cause memory leaks.
Remember:
The dynamic space must be released and released correctly
4. Memory development of C / C + + program
Several areas of C/C + + program memory allocation:
1. Stack: when executing a function, the storage units of local variables in the function can be created on the stack, and these storage units will be automatically released at the end of function execution. Stack memory allocation 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, return data, return address, etc. allocated for running the function.
2. heap: it is generally 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 a linked list.
3. The data segment (static area) stores global variables and static data. Released by the system at the end of the program.
4. Code segment: the binary code that stores the function body (class member function and global function).
With this picture, we can better understand the example of static keyword modifying local variables in the introduction to C language.
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 leave the 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.
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 a "flexible array" member.
For example:
typedef struct st_type { int i; int a[0];//Flexible array member }type_a; Some compilers will report errors and cannot compile. You can change it to: typedef struct st_type { int i; int a[];//Flexible array member }type_a;
Features 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 greater than the size of the structure
Small to accommodate the expected size of the flexible array.
//code1 typedef struct st_type { int i; int a[0];//Flexible array member }type_a; printf("%d\n", sizeof(type_a));//The output is 4
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);
In this way, the flexible array member a is equivalent to obtaining a continuous space of 100 integer elements.
Advantages of flexible arrays
Type above_ 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; } //Free up space free(p->p_a); p->p_a = NULL; free(p); p = NULL;
The above code 1 and code 2 can perform the same function, but the implementation of method 1 has two advantages:
The first advantage is to facilitate 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 members in the structure also need free
So you can't expect users to find out. Therefore, if we divide the memory of the structure and the memory of its members at one time
After configuration, a structure pointer is returned to the user, and the user can free all memory once.
The second advantage is: 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, on the contrary
If you can't run, you need to add the offset to address it)