您的位置:首页 > Web前端

a function return a pointer , wherein a bug

2012-05-04 09:25 239 查看
点击打开链接

Those are the two most common reasons for passing a pointer to a function as an argument. However, pointers can also be returned from functions. The syntax is consistent with all other declarations for a pointer, but there are
a few pitfalls in returning pointers that should be discussed. These pitfalls apply to pointers as arguments, though it is not as easy to fall into the traps that way. The first, and foremost, pitfall of returning pointers is returning a pointer to local memory.
Most of the time this falls under the desire to return a scratch array used to transform an argument:

 1 #include <stdio.h>
2 #include <string.h>
3
4 char *reverse ( const char *s )
5 {
6 char save[1024];
7 int i = 0, j = strlen ( s );
8
9 while ( j > 0 )
10 save[i++] = s[--j];
11 save[i] = '\0';
12
13 return save; /* Wrong! */
14 }
15
16 int main ( void )
17 {
18 char *p = reverse ( "J. Random Guy" );
19
20 puts ( p );
21
22 return 0;
23 }
While this code will compile and run, the most likely output will be garbage characters. Why? Because
p points to memory that was local to reverse, and when
reverse returned control to main, that memory was released for other uses. Therefore, the memory that
p points to no longer belongs to the program. There are three solutions to the problem. First, you can make the local array static, thus forcing the lifetime of the array to be that of the entire program. Since the problem was that the lifetime
of the array was local to reverse, and ended when reverse ended, this is a quick fix since it only requires that the keyword
static be prepended to the declaration of the local array:

 1 #include <stdio.h>
2 #include <string.h>
3
4 char *reverse ( const char *s )
5 {
6 static char save[1024];
7 int i = 0, j = strlen ( s );
8
9 while ( j > 0 )
10 save[i++] = s[--j];
11 save[i] = '\0';
12
13 return save; /* Safe now */
14 }
15
16 int main ( void )
17 {
18 char *p = reverse ( "J. Random Guy" );
19
20 puts ( p );
21
22 return 0;
23 }
Unfortunately, static local variables are more trouble than they are worth. First, this new
reverse function will not play well in a multi-threaded environment because there is only one copy of the array even though it appears to be on the stack at first glance. Second, and for the same reason, the string that is returned from
reverse must be immediately used and then forgotten, or immediately copied. Otherwise a future call to
reverse will overwrite the contents of the array, and the result of the last call will be lost:

 1 int main ( void )
2 {
3 char *p;
4
5 p = reverse ( "J. Random Guy" );
6 reverse ( "This is a test" );
7 puts ( p );
8
9 return 0;
10 }
The result will be, unintuitively, “tset a si sihT”, because the second call to
reverse caused the static array to be overwritten with the new string. Several POSIX functions have this very problem because of a local static variable, and many a curse has been uttered because of it. The next solution does not have this
problem because it forces the calling function to supply a buffer. Naturally, this requires another argument to the function, and the calling function can then create a local array to pass to it:

 1 #include <stdio.h>
2 #include <string.h>
3
4 void reverse ( const char *s, char buffer[] )
5 {
6 int i = 0, j = strlen ( s );
7
8 while ( j > 0 )
9 buffer[i++] = s[--j];
10 buffer[i] = '\0';
11 }
12
13 int main ( void )
14 {
15 char buffer[1024];
16
17 reverse ( "J. Random Guy", buffer );
18 puts ( buffer );
19
20 return 0;
21 }
Using a buffer argument and returning a pointer to that buffer can be a powerful combination:

 1 #include <stdio.h>
2 #include <string.h>
3
4 char *reverse ( const char *s, char buffer[] )
5 {
6 int i = 0, j = strlen ( s );
7
8 while ( j > 0 )
9 buffer[i++] = s[--j];
10 buffer[i] = '\0';
11
12 return buffer;
13 }
14
15 int main ( void )
16 {
17 char buffer[1024];
18 char *p;
19
20 p = reverse ( "J. Random Guy", buffer );
21 puts ( buffer );
22 puts ( p );
23
24 return 0;
25 }
The third common solution to the original problem is to dynamically allocate memory inside
reverse, and then return a pointer to that memory. Because dynamic memory has a lifetime of from when it is explicitly allocated to when it is explicitly freed, it will exist until the calling function calls
free on the pointer:

 1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 char *reverse ( const char *s )
6 {
7 int i = 0, j = strlen ( s );
8 char *save = malloc ( j + 1 );
9
10 if ( save == NULL )
11 return NULL;
12
13 while ( j > 0 )
14 save[i++] = s[--j];
15 save[i] = '\0';
16
17 return save;
18 }
19
20 int main ( void )
21 {
22 char *p;
23
24 p = reverse ( "J. Random Guy" );
25 puts ( p );
26 free ( p );
27
28 return 0;
29 }
The problem with this solution is that it requires the calling function to remember to free the memory. Unless the calling function explicitly allocates memory, it is unlikely that the programmer will remember to free it, especially
if the allocation is hidden in a function. Therefore, of the three solutions, passing a buffer to the function is the best option most of the time.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息