Introduction for anyone who uses C language, if asked what the biggest annoyance of C language is, many of them may be answering pointers and memory leaks. These are really things that consume most of the developer's debugging time. Pointers and memory leaks may seem daunting to some developers, but once you understand the basics of pointers and their associated memory operations, they are the most powerful tools you have in C.
This article will share with you the secrets that developers should know before starting to use pointers for programming. The contents of this article include:
Type of pointer action that causes memory corruption
Checkpoints that must be considered when using dynamic memory allocation
Scenarios that cause memory leaks if you know in advance what might go wrong, you can be careful to avoid traps and eliminate most of the pointer-and memory-related issues.
Where could something go wrong? Several problem scenarios may occur, which can cause problems after the build is complete. As you work with pointers, you can use the information in this article to avoid many problems.
Uninitialized memory in this example, P has been assigned 10 bytes. These 10 bytes may contain garbage data, as shown in 1.
Char *p = malloc (10); Figure 1. Junk data
If a piece of code tries to access it before it is assigned a value, you might get garbage, and your program might behave in unpredictable behavior. P may have values that your program has never expected.
Good practice is to always use memset and malloc together, or use calloc.
Char *p = malloc (P, ', 10); now, even if the same code snippet tries to access it before assigning a value to P, the snippet also correctly handles the Null value (which should ideally be the value) and then has the correct behavior.
Memory overwrite because P has been assigned 10 bytes, if a snippet tries to write a 11-byte value to p, the action will automatically "eat" a byte from a different location without telling you. Let's assume that the pointer q represents that memory.
Figure 2. Original Q content
Figure 3. Post-Coverage Q content
As a result, pointer Q will have something that has never been expected. Even if your module is well-coded, it may behave incorrectly due to certain memory operations performed by a co-existing module. The following sample code snippet can also illustrate this scenario.
Char *name = (char *) malloc (11); Assign some value to namememcpy (p,name,11); Problem begins here in this example, the memcpy operation attempts to write 11 bytes to p, and the latter is only assigned 10 bytes.
As a good practice, whenever you write a value to a pointer, make sure that you cross-check the number of bytes available and the number of bytes written. In general, the memcpy function will be the checkpoint for this purpose.
Memory read out-of-bounds memory read out (Overread) refers to the number of bytes read more than they should have. The problem is not too serious and is not detailed here. The following code provides an example.
Char *ptr = (char *) malloc (n); char name[20]; memcpy (name,ptr,20); Problem begins here in this example, the memcpy operation attempts to read 20 bytes from PTR, but the latter is only assigned 10 bytes. This can also lead to unwanted output.
Memory leaks in memory leaks can be really annoying. The following list describes some scenarios that cause a memory leak.
Re-assignment I'll use an example to illustrate the problem of re-assignment. Char *memoryarea = malloc (n), char *newarea = malloc (10), which assigns a value to the memory location shown in Figure 4 below.
Figure 4. Memory location
Memoryarea and Newarea are assigned 10 bytes, respectively, as shown in their respective content 4. If someone executes a statement such as the following (pointer re-assigned value) ...
Memoryarea = Newarea; it will certainly cause trouble for you in the subsequent stages of the development of this module.
In the preceding code statement, the developer assigns the Memoryarea pointer to the Newarea pointer. As a result, the memory location previously pointed to by Memoryarea becomes orphaned, as shown in Figure 5 below. It cannot be freed because there is no reference to that location. This results in a 10-byte memory leak.
Figure 5. Memory leaks
Make sure that the memory location does not become orphaned before you assign a value to the pointer.
The first release of the parent block assumes that there is a pointer to Memoryarea, which points to a 10-byte memory location. The third byte of the memory location points to a dynamically allocated 10-byte memory location, as shown in 6.
Figure 6. Dynamically allocated memory
Free (Memoryarea) If the Memoryarea is freed by calling the "no", the Newarea pointer becomes invalid as a result. The memory location that Newarea previously pointed to cannot be freed because there is no pointer to that location. In other words, the memory location that Newarea points to is orphaned, causing a memory leak.
Whenever a structured element is disposed, and the element contains a pointer to a dynamically allocated memory location, the child memory location (in this case, Newarea) should be traversed first, and then released from there and then traversed back to the parent node.
The correct implementation here should be:
Free (memoryarea->newarea); memoryarea; incorrect handling of return values
Sometimes, some functions return a reference to dynamically allocated memory. Tracking the memory location and handling it correctly becomes the responsibility of the calling function.
Char *func () {return malloc ()//Make sure to memset this ocation to ' ...} void Callingfunc () {func ();//Problem lies here} in the above example, the call to the Func () function in the Callingfunc () function did not process the return address of the memory location. As a result, the 20-byte block allocated by the Func () function is lost and causes a memory leak.
Return what you get when developing components, there may be a lot of dynamic memory allocations. You may forget to track all pointers (pointing to these memory locations), and some memory segments are not released and remain assigned to the program.
Always keep track of all memory allocations and release them at any appropriate time. In fact, you can develop a mechanism to track these allocations, such as keeping a counter in the list node itself (but you must also consider the additional overhead of the mechanism).
Access to a null pointer is very dangerous because it may crash your program. Always make sure that you are not accessing a null pointer.
Summary This article discusses several pitfalls that you can avoid when using dynamic memory allocation. To avoid memory-related problems, good practice is:
Always use memset and malloc together, or always use calloc.
Whenever you write a value to a pointer, be sure to cross-check the number of bytes available and the number of bytes written.
Make sure that no memory location becomes orphaned before you assign a value to the pointer.
Whenever you release a structured element that contains a pointer to a dynamically allocated memory location, you should first traverse the child memory location and start releasing it from there, and then traverse back to the parent node.
function return values that return dynamically allocated memory references are always handled correctly.
Each malloc must have a corresponding free.
Make sure that you are not accessing a null pointer.
Pointers and memory leaks in the C language