a function return a pointer , wherein a bug

点击打开链接

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.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值