Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3516041
  • 博文数量: 864
  • 博客积分: 14125
  • 博客等级: 上将
  • 技术积分: 10634
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-27 16:53
个人简介

https://github.com/zytc2009/BigTeam_learning

文章分类

全部博文(864)

文章存档

2023年(1)

2021年(1)

2019年(3)

2018年(1)

2017年(10)

2015年(3)

2014年(8)

2013年(3)

2012年(69)

2011年(103)

2010年(357)

2009年(283)

2008年(22)

分类: C/C++

2009-07-30 17:54:22

先看一个例子:
 1#include <stdio.h>
 2#include <stdlib.h>
 3#include <string.h>
 4
 5char* fun(const char* src)
 6{
 7  static char dest[32= "";
 8  
 9  strcpy(dest, src);
10
11  return dest;
12}

13
14int main()
15{
16  char s1[32= "";
17  char s2[32= "";
18
19  strcpy(s1, fun("hello"));
20  strcpy(s2, fun("world"));
21
22  printf("%s %s\n", s1, s2);
23  printf("%s %s\n", fun("hello"), fun("world"));
24
25  return 0;
26}

    读一下这个程序,先看这个程序写的有问题没(假设fun函数的参数长度小于32)?如果你对这个程序中的fun函数返回一个局部变量的数组产生了疑问,那么我希望你是没注意到我使用的static类型,若你仍有疑问,建议你先回去查查static变量的作用域和生命周期的概念。
    OK,是运行这个程序的时候了,看一下运行结果是否跟你想象的一样呢?如果是一样的,那么这篇文章你不用看了,因为你已经掌握了我下面要说的问题了。好吧,对于不理解运行结果的朋友,我们来分析一些下面那个printf语句,首先要知道printf中的表达式、函数的执行顺序是至右向左的,也就是先执行了fun("world")返回了dest的地址,然后再执行fun("hello")也返回了dest的地址,而这两次返回的dest用的同一块地址(因为是static类型),也就是第二次的执行覆盖了第一次执行的结果,对dest地址进行了重新的赋值,所以结果就是打印两个hello了。


    我们在写C/C++程序的时候,经常需要从调用函数中取得自己想要的数据,这就需要调用者和函数之间要有个内存的交互,我们通常采用的方法是传递一个指针给被调函数,作为被调函数的输出参数,这也是我们常用的、规范的做法。
    但有很多程序员比较习惯直接取返回值,这就面临一个问题就是普通局部变量都是在栈上分派的,会随着函数的结束而弹栈释放,那么就会出现返回局部变量数组的问题,这时有人会想到用malloc或new在堆上分派内存,没错,这样是避免了前面说的问题,但这样又会带来新的问题,就是需要在外部对这块内存进行释放,这个是比较难把握的,多次释放会出现程序的crash,忘记释放了会出现内存leak,所以这种方法也不被推荐。还有人想到了更另类的方法,就是上面例子中的static类型,没错,static变量也是全局的,但就会出现上面程序的运行结果(可以认为不是我们想要的结果,也就是错误的结果)。
    所以,我们要慎用返回函数内部的static内存的这种设计,但如果在无法改变设计模式的情况下(有些系统函数的实现,比如inet_ntoa,可以通过在man手册中看到这样的一句话:The string is returned in a statically allocated buffer, which subsequent calls will overwrite),那么在自己使用的时候一定要注意,不要试图保存返回的内存地址或引用,而要保存返回内存的内容,也就是例子程序中的strcpy两行。

inet_ntoa的错误使用(判断两个IP地址是否相等):

 1struct in_addr addr1;
 2struct in_addr addr2;
 3
 4// 网络包中包含了源地址
 5addr1.s_addr = 0x6500A8C0 // 192.168.0.101
 6addr2.s_addr = 0x6600A8C0 // 192.168.0.102
 7
 8// 这个if语句将永远为真
 9if (strcmp(inet_ntoa(addr1), inet_ntoa(addr2)) == 0{
10  // do something
11}
 else {
12  // do other thing
13}
阅读(969) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~