I personally like the concept of pointers because they are very useful and efficient in many ways, such as in a tree data structure. Furthermore, it helps me better understand how the code works at the low level in more details; it is my belief that a good programmer should know both the low level and high level sides of a system.
At the same time, I admit that one needs to be very careful with pointers because improper use of pointers will lead to a disaster. Here, I would like to give an example of such improper use of a pointer that will lead to memory leak.
People often interchangeably use pointers and arrays. Below is example1.c code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
int main () { | |
char *str1 = "pppp"; | |
char str2[] = "aaaa"; | |
printf ("%s\n%s\n", str1, str2); | |
return 0; | |
} |
The code compiles with no error or warning:
$ gcc example1.c -o example1 && ./example1
pppp
aaaa
OK. As you may have expected, the string can be either a pointer or an array; there seems nothing wrong with this. So, is it true that you can interchangeably use the pointer or the array to define a string? The answer is NO.
In the above example, str1 is a pointer to "pppp", which is allocated outside the function main stack. In other words, the variable str1 is a local variable in main, but it points to "pppp" that is saved in the memory outside the main's scope. On the other hand, str2 is a local variable array which saves the string value "aaaa".
Let's examine the memory using gdb. Before that, we need to compile the source with -g option in gcc to supply symbols:
$ gcc -g example1.c -o example1
Next, run gdb and examine str1 and str2:
$ gdb -q example1
Reading symbols from example1...done.
(gdb) b 6
Breakpoint 1 at 0x80484b3: file example1.c, line 6.
(gdb) r
Starting program: /home/linuxnme/Documents/
pppp
aaaa
Let's examine the memory content of &str1
(gdb) x/wx &str1
0xbffff570: 0x08048560
(gdb) x/s str1
0x8048560: "pppp"
Let's examine &str2 now.
(gdb) x/wx &str2
0xbffff577: 0x61616161
(gdb) x/s &str2
0xbffff577: "aaaa"
Can you tell the difference now? Let's quit gdb with
(gdb) q
(gdb) q
Quit anyway? (y or n) y
Now in order to examine memory leakage, let's consider example2.c code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
char* array() { | |
char string[] = "aaaa"; | |
return string; | |
} | |
char* ptr() { | |
char *string = "pppp"; | |
return string; | |
} | |
int main() { | |
printf ("%s\n", array()); | |
printf ("%s\n", ptr()); | |
return 0; | |
} |
Let's compile and run it. When compiling the code, your compiler should warn you that the function returns the address of the local variable.
$ gcc example2.c -o example2 && ./example2
?
pppp
As you can see, when a string is defined as an array in a local function, it is saved in the function's stack and therefore it is completely cleared out when the function returns. However, if a string is defined as a pointer, then the string is saved outside the function's scope, and therefore it will remain in the memory. This is the memory leak in the program. Here, it is only a 5-byte memory leak, but it can get worse very quickly if the function is called multiple times during its run. Although I only demonstrated this with a char string, it could be of any data types including structures or classes.
So, the main lesson here is never define anything directly from a pointer, especially in a local function because it will lead to memory leak.
No comments:
Post a Comment