Introduction
For anyone using the C language, ask them what the biggest annoyance of C is, and many of them may respond with pointers and memory leaks. These are really the things that cost developers most of their debugging time. Pointers and memory leaks 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 the C language.
This article will share with you the secrets developers should know before they start using pointers to program. This article includes: a scenario where the type of pointer operation that causes memory damage must be considered when using dynamic memory allocation to cause a memory leak
If you know in advance what can go wrong, you can be careful to avoid traps and eliminate most of the problems associated with pointers and memory. There may be a mistake somewhere.
There are several problem scenarios that may occur that may cause problems after the build is completed. When working with pointers, you can use the information in this article to avoid many problems. Uninitialized Memory
In this case, p has been allocated 10 bytes. These 10 bytes may contain garbage data, as shown in Figure 1.
Char *p = malloc (10);
Figure 1. Garbage Data
If a code snippet tries to access it before assigning a value to this p, you may get a garbage value, and your program may have unpredictable behavior. P may have a value that your program never expected.
Good practice is to always combine use of memset and malloc, or use calloc.
Char *p = malloc (a);
memset (P, ', 10);
Now, even if the same code snippet tries to access it before assigning a value to P, the code snippet can handle the Null value correctly (the value that it should ideally have) and then have the correct behavior. Memory Overwrite
Since P has been allocated 10 bytes, if a code fragment attempts to write a 11-byte value to p, the operation will automatically "eat" a byte from another location without telling you. Let's assume that pointer Q represents that memory. Figure 2. Original Q content
Figure 3. Post-Overlay Q content
As a result, the pointer Q will have something that is never expected. Even if your module is well coded, it may have incorrect behavior due to some memory manipulation performed by a coexistence module. The following sample code fragment can also illustrate this scenario.
Char *name = (char *) malloc (one);
Assign some value to name
memcpy (p,name,11);//Problem begins
In this case, the memcpy operation attempts to write 11 bytes to p, the latter being allocated only 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 of bounds (overread) means that the number of bytes read is more than the number of bytes they should have. The problem is not so serious that it is no longer detailed here. The following code provides an example.
Char *ptr = (char *) malloc (a);
Char name[20];
memcpy (name,ptr,20); Problem begins here
In this case, the memcpy operation attempted to read 20 bytes from PTR, but the latter was assigned only 10 bytes. This also results in an expected output. Memory Leaks
Memory leaks can be really annoying. The following list describes some scenarios that cause memory leaks. Re-assign a value I'll use an example to illustrate the problem of the assignment.
Char *memoryarea = malloc (a);
Char *newarea = malloc (10);
This assigns a value to the memory location as shown in Figure 4 below. Figure 4. Memory location
Memoryarea and Newarea are assigned 10 bytes, each of which is shown in Figure 4. If someone executes the statement (pointer reassign) as shown below ...
Memoryarea = Newarea;
Then it's definitely going to be a problem for you in the next phase of the module development.
In the above code statement, the developer assigns the Memoryarea pointer to the Newarea pointer. As a result, the memory location that Memoryarea previously pointed to becomes orphaned, as shown in Figure 5 below. It cannot be freed because there is no reference to that location. This can result in a 10-byte memory leak. Figure 5. Memory Leaks
Make sure that the memory location does not become orphaned until you assign the pointer. First, let's release the parent block. Suppose you have a pointer 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 Figure 6.
Figure 6. Dynamically allocated Memory
Free (Memoryarea)
If Memoryarea is freed by calling free, the Newarea pointer becomes invalid as well. 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, resulting in a memory leak.
Whenever you release a structured element that contains a pointer to a dynamically allocated memory location, you should first traverse the child memory location (in this case, Newarea) and start releasing it and then traversing back to the parent node.
The correct implementation here should be:
Free (memoryarea->newarea);
Free (Memoryarea);
Improper 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 location to ' ...
}
void Callingfunc ()
{
func ();//Problem lies here
}
In the previous example, the call to the Func () function in the Callingfunc () function did not handle 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 have received
When developing components, there may be a large number of dynamic memory allocations. You may forget to keep track of all the pointers (pointing to these memory locations), and some of the memory segments are not released and remain assigned to the program.
Always keep track of all memory allocations and release them whenever appropriate. In fact, you can develop a mechanism to track these allocations, such as keeping a counter in the linked list node itself (but you must also consider the additional overhead of the mechanism). Access NULL pointer
Access to a null pointer is very dangerous because it can cause your program to crash. Always make sure that you are not accessing the null pointer. Summary
This article discusses several pitfalls that can be avoided when using dynamic memory allocations. To avoid memory-related problems, it's good practice to always use memset and malloc, or always use calloc. 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. Before assigning to pointers, make sure that no memory locations become orphaned. 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 before traversing back to the parent node. A function return value that returns dynamically allocated memory references is always handled correctly. Each malloc must have a corresponding free. Make sure that you are not accessing the null pointer.