Introduction
Original address: http://www.cnblogs.com/archimedes/p/c-point-memory-leak.html, reprint Please indicate the source address.
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.
Common memory errors and their countermeasures are as follows:
1, the memory allocation is not successful, but used it
Novice programmers often make this mistake because they are unaware that the memory allocation will not succeed. A common workaround is to check if the pointer is NULL before using memory . If the pointer p is a function parameter, then the function
The entrance is checked with an assert (P!=null). If you are using malloc or new to request memory, you should use if (p==null) or if (p!=null) for error-proof handling.
2. The memory allocation succeeds, but it is not initialized to reference it
There are two main causes of this error: one is the idea of no initialization, and the other is to mistakenly assume that the default initial value of the memory is all zero, resulting in a reference to the initial error (for example, an array).
There is no uniform standard for what the default initial value of memory is, although sometimes it is a zero value and we would rather believe it to be credible. So no matter how you create an array, don't forget to assign the initial value, even if it's 0.
The value can not be omitted, do not be too troublesome.
3. The memory allocation succeeds and has been initialized, but the operation crosses the memory boundary
For example, the use of arrays often occurs when the subscript "more 1" or "less 1" operation. Especially in a For loop statement, the number of loops can be easily mistaken, resulting in array operations being out of bounds.
4, forget to release memory, causing memory leaks
The function that contains this error loses one piece of memory each time it is called. At first, the system has plenty of memory and you can't see the error. One time the program suddenly died, the system appears prompt: memory exhaustion.
Uninitialized memory
In this example, p
10 bytes have been allocated. These 10 bytes may contain garbage data, as shown in 1.
Char *p = malloc (10);
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 (P, ' memset ', 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.
Char *name = (char *) malloc (11); Assign some value to namememcpy (p,name,11); Problem begins here
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.
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) ...
Memoryarea = Newarea;
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.
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 the "to" ...} 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 that you are not accessing a null pointer.
Pointers and memory leaks in C language in several cases