Foreword: Why is there dynamic memory allocation?
We already know how to open up memory as follows
int a=10;//Open up 4 bytes on stack space char arr[10]={0};//Open up 10 bytes of continuous space on stack space
The above method of opening up space has two drawbacks:
1. The size of space development is fixed.
2. Arrays must be declared with an array length that requires memory allocated at compile time.
But space requirements are not just those. Sometimes the size of space we need is not known until the program is running, and then the above methods can't meet our needs. Let's introduce a solution: dynamic memory allocation
1. Dynamic Memory Functions
(Picture from Bit Employment class)
When a computer is in use, it has three zones: the common stack zone, which stores local variables and function-form parameters; the static zone, which stores static and global variables; and the last heap zone, which we use for dynamic memory allocation, must master the following four functions to learn dynamic memory allocation:
1.malloc and free functions
The malloc function declaration:
void*malloc(size_t size);//size_t is unsigned int
This function requests a contiguous free space from memory and returns a pointer to the space.
1. If the opening is successful, return a pointer to the opening space
2. Return a NULL pointer if the development fails
(Since it is a NULL pointer, check the assert commonly used for malloc functions)
3. The return value type is void*, so the type of space the malloc function opens up needs to be determined by the user himself
4. If size=0, malloc's behavior depends on the specific compiler
free function declaration
void free(void*ptr);
The free function is used to free up dynamically exploited space, with the following points in mind:
1. If the space pointed to by the parameter ptr is not dynamically exploited, the behavior of the free function is unknown.
2. If ptr is a null pointer, the free function does nothing
Examples of actual warfare:
#include<stdio.h> #Include <stdlib.h>//malloc and free function header files int main() { int*p=(int*)malloc(40);//The space created by malloc is of indeterminate type and you need to force a type yourself //Here we convert it to int*, and the space is maintained by an integer pointer //So here's 4 bytes as one element, 40 bytes, and 10 int s to fill in if (p == NULL) { return -1; }//If no value is returned, the development is successful int i = 0; for (i = 0;i < 10;i++) { *(p + i)=i;//Assigning operations to open up space } free(p);//When it's finished, use the free function to free up the space p points to (40 bytes all, back to the operating system) p = NULL;//Since P stores open-space addresses, even if space is returned to the operation form, P can still find this space, which is dangerous, so we assign p a null pointer return 0; }
2.calloc function
The calloc function is also used for dynamic memory allocation and is declared as follows
void*calloc(size_t num,size_t size)
This function opens up a space for num size size elements and initializes each byte of space to zero
It differs from the malloc function only by initializing each byte in the request space to zero before returning the address
The code is as follows (example):
#include<stdio.h> #Include <stdlib.h>//calloc function header file #Include <string.h>//strerror function header file #Include <errno.h>//errno header file int main() { int*p = (int*)calloc(10, sizeof(int));//Open up 10 spaces of int size if (p == NULL)//The calloc function may also fail to open up space and needs to be tested { printf("%s\n", strerror(errno));//errno is an error code, strerror converts the error code to the appropriate error message return -1; } int i = 0; for (i = 0;i < 10;i++) { printf("%d ", *(p + i));//Will print 10 0 (calloc will initialize itself to 0) } free(p); p = NULL; return 0; }
2.realloc functions
The realloc function is a function that appends the application space when there is not enough space available. It is declared as follows:
void*realloc(void*memblock,size_t size);
The realloc function is designed to make dynamic memory management more flexible. Sometimes we find that the space we have previously applied for is too small or too large. We can use the realloc function to increase or decrease it. The following points should be noted:
1.ptr is the memory address to be adjusted
2.size is the new size after adjustment
3. The return value is the adjusted memory start position
4. On the basis of resizing the original memory, the function also copies the original memory data to the new space.
5.realloc functions exist in two cases when adjusting memory space
Explanations for 4 and 5 are as follows:
Suppose we now double the space
First: As shown above, red is the space we have opened up and blue is the space being used by other programs. What if we want to open up a space that is physically continuous, we cannot use the blue part, and the space in the middle is not twice as large as the original space?
We'll find another place with enough space to double the original space, copy the data from the original space to the new space, and the function returns the address of the new space.
Second: This is simpler. After the original space, it is enough to open up a space twice as much as the original space. We can just open it up directly.
The function returns the first address of the original space directly.
Of course, realloc functions, like malloc and calloc functions, can also fail to open up space, so you still need to check if a null pointer is returned
#include<stdio.h> #Include <stdlib.h>//malloc and free function header files int main() { int*p=(int*)malloc(40);//Open up 10 int-sized spaces int i = 0; for (i = 0;i < 10;i++) { *(p + i)=i;//Assigning operations to open up space } int*ptr = realloc(p, 20 * sizeof(int));//Note! Here 20*sizeof(int) is the new size //For example, I only have 10 now, and I need 20, which is 10 behind. But instead of writing 10 here, I write a new size of 20. if (ptr != NULL) { p = ptr; } for (i = 10;i < 20;i++)//Assignment of new open space { *(p + i) = i; } for (i = 0;i < 20;i++) { printf("%d ", *(p + i));//Print 0-19 } free(p); p = NULL; return 0; }
2. Common Errors
1. Unreferencing NULL pointers
The code is as follows (example):
#include<stdio.h> #include<stdlib.h> int main() { int*p = (int*)malloc(20); *p = 0;//Unreference the address p and assign it a value of 0 free(p); return 0; }
Functions such as malloc are likely to fail when opening up space. In case of failure, it is to return the null pointer. It must be problematic for you to dereference and assign values directly to the null pointer.
So we're still going to do pointer checking here
The code is as follows (example):
#include<stdio.h> #include<stdlib.h> int main() { int*p = (int*)malloc(20); if(p==NULL) { return -1; //If returned, open a failed end program, if not returned, you can do the following } *p = 0;//Unreference the address p and assign it a value of 0 free(p); return 0; }
2. Cross-border access to dynamic open space
The code is as follows (example):
#include<stdio.h> #include<stdlib.h> int main() { int*p = (int*)malloc(200);//200 bytes or 50 int s if (p == NULL) { return -1; } int i = 0; for (i = 0;i < 60;i++) { *(p + i) = i; } free(p); p = NULL; return 0; }
At first glance, this code looks OK, but if you look closely, you'll see that malloc has 200 bytes of space, or 50 int s. You can only assign a maximum of 50 loops to a for loop. You must have made 60 cross-border visits. This is also a proper error report.
3. Use free functions for non-dynamic development
The code is as follows (example):
#include<stdio.h> #include<stdlib.h> int main() { int a = 10; int*p = &a; free(p); p = NULL; }
Here, int creates a, assigns the address of a to p of type int*, and then freedrops p. This is also a sure error, p is a local variable on the stack, and the free function is for the stack area
4. Use free to free up a piece of dynamic memory to open up a portion of the memory
The code is as follows (example):
//Use free to free up a piece of dynamic memory to open up a portion of memory #include<stdio.h> #include<stdlib.h> int main() { int*p = (int*)malloc(10 * sizeof(int)); if (p == NULL) { return -1; } //Use int i = 0; for (i = 0;i < 5;i++) { *p++ = i; } //release free(p); p = NULL; }
What's wrong with the code here? Let's draw a picture and see.
Initially P is at the top position, but with the for loop, p++, the position P points to keeps going backwards until it reaches the bottom position
Now that p is no longer pointing to the original open space, it is obviously inappropriate for you to release it with free at this time.
5. Release the same space multiple times
Let's start with two pieces of code:
#include<stdio.h> #include<stdlib.h> int main() { int*p = (int*)malloc(40); if (p == NULL) { return -1; } free(p); free(p); }
#include<stdio.h> #include<stdlib.h> int main() { int*p = (int*)malloc(40); if (p == NULL) { return -1; } free(p); p = NULL; free(p); }
Both pieces of code are freed multiple times for the same block of space, but the first one will fail and the second one will not.
Explain as follows:
The first piece of code you've freed up the space P points to. There's nothing left in the space, but p still points to that space, so it's bound to be an error if you free up the space that doesn't belong to you again.
The second code frees up the space that P points to, assigns a value to p with the null pointer, and releases the null pointer. We know that the free null pointer does nothing, so it doesn't error.
6. Dynamic Opening Memory Forgot Release
For dynamic open memory forgot to release, there are two ways to reclaim the space requested on the heap:
1. free yourself
2. When the program exits, the system recycles automatically
Let's start with a piece of code
#include<stdio.h> #include<stdlib.h> int main() { int*p = (int*)malloc(40); if (p == NULL) { return -1; } getchar(); return 0; }
This code we don't use free to free up memory, and getchar is waiting to receive characters in the middle. For example, if you go to the toilet halfway or do something else and getchar doesn't receive characters, the program will never end. The space we use p has been occupied while you are in the toilet, and that space system can't do anything else.Significant things. Up to the corporate level in the future: The programs we write may be running 24 hours a day. That happens when you don't lose memory freely, you don't have to recycle it, and overall efficiency has a big impact.
summary
Today, we introduced the dynamic memory allocation function and some common errors in dynamic memory allocation. We hope that the reader can get some benefit from learning. We wish the reader success in his studies and all the best!