When using C, are you tired of spending time debugging pointers and memory leaks? If so, then this article is for you. You will learn about the types of pointer operations that can lead to memory corruption, and you will examine scenarios to understand what to consider when using dynamic memory allocations.
Introduction
For anyone using C language, if asked what the biggest annoyance of C language is, many of them might answer 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 can go wrong, you can be careful to avoid traps and eliminate most of the pointers 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
10 bytes have been allocated. These 10 bytes may contain garbage data, as shown in 1.
Figure 1. Junk data
If p
a snippet tries to access it before it is assigned to it, it may get garbage values, and your program may have unpredictable behavior. p
may have a value that your program has never expected.
Good practice is always used in combination memset
with malloc
, or used calloc
.
char *p = malloc; memset (P, '/0 ', 10); |
Now, even if the same piece of code tries to p
access it before it is assigned, the snippet also handles the Null
value correctly (ideally, the value it should have) and then has the correct behavior.
Memory overwrite
Since p
10 bytes have been allocated, if a code fragment tries to p
write a 11-byte value, the action will automatically "eat" a byte from a different location without telling you. Let's assume q
that the pointer represents that memory.
Figure 2. Original Q content
Figure 3. Post-Coverage Q content
As a result, the pointer q
will have something that was never 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.
In this case, the memcpy
operation attempted to write 11 bytes p
, and the latter was 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-of-bounds (overread) refers to the number of bytes read more than the number of bytes 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 ptr
read from 20 bytes, but the latter is only assigned 10 bytes. This can also lead to unwanted output.
Memory leaks
Memory leaks can be really annoying. The following list describes some scenarios that cause a memory leak.
- Re-assign Value
I'll use an example to illustrate the question of re-assignment.
Char *memoryarea = malloc (n), char *newarea = malloc (10); |
This assigns a value to the memory location shown in Figure 4 below.
Figure 4. Memory location
memoryArea
and newArea
respectively are assigned 10 bytes, which are shown in their respective content 4. If someone executes a statement such as the following (pointer re-assigned value) ...
It will certainly bring you trouble in the next stages of the module development.In the preceding code statement, the developer assigns the memoryArea
pointer to the pointer newArea
. As a result, the memoryArea
previously pointed memory location 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.
- First release the parent block
Suppose you have a pointer memoryArea
that 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
If you release by calling Free memoryArea
, the newArea
pointer becomes invalid as a result. newArea
the memory location pointed to previously cannot be freed because there are no pointers to that location. In other words, the newArea
location of the pointing memory becomes orphaned, resulting in a memory leak.
Whenever a structured element is released, and the element contains a pointer to a dynamically allocated memory location, the child memory location (in this case) should be traversed first, newArea
and then freed from there and then traversed back to the parent node.
The correct implementation here should be:
Free (Memoryarea->newarea), free (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 calling
function's responsibility.
Char *func () {return malloc (+);//Make sure to memset this location to '/0 ' ...} void Callingfunc () {func ();//Problem lies here} |
In the previous example, the callingFunc()
call to the function in the function func()
did not process the return address of the memory location. As a result, the func()
20-byte block allocated by the function is lost and causes a memory leak.
Return what you have obtained.
There may be a lot of dynamic memory allocations when developing components. 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).
Accessing a null pointer
Accessing a null pointer is dangerous because it can cause your program to crash. Always make sure that you are not accessing a null pointer.
Summarize
This article discusses several pitfalls that you can avoid when using dynamic memory allocation. To avoid memory-related problems, good practice is:
- Always use together
memset
and malloc, 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 you are not accessing the null finger
http://blog.csdn.net/adcxf/article/details/2288073
Pointers and memory leaks in the C language