https://github.com/zytc2009/BigTeam_learning
分类: C/C++
2009-07-30 17:54:22
读一下这个程序,先看这个程序写的有问题没(假设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地址是否相等):