ChinaUnix.net
 >> ChinaUnix.net > C/C++

求救!一个简单的问题!!

作者:suyer     发表时间:2001/12/20 09:15am

char * getstr(){
   char tmpstr[255];
   
   strcpy(tmpstr,"------");
   return tmpstr;
}
为什么编译出现:
function returns address of local variable!
究竟什么意思?为什么返回本地地址就不可以?
请教各位了!
系统是REDHAT 7。1

此文章相关评论:
该文章有42个相关评论如下:(点这儿可以发表评论)
nico 发表于: 2001/12/20 09:34am
我也不太清楚,不过你试试下面这条语句:
return &tmpstr;
或者写成
return &tmpstr[0];
 
 
taodale 发表于: 2001/12/20 09:50am
如果你学过编译原理的话,对这个问题就会很清楚了。
你在函数里所定义的一个变量是临时变量,如char tmpstr[255]; 它仅在函数的生存期内有效。临时变量在函数被调用的时候分配所需的存储空间,在函数返回以后,这块空间会被系统收回派其它用场,所以返回它没有任何意义。
正确的用法是:
char * getstr(){
  char* tmpstr;
 
  tmpstr=(char*) malloc(255);
  strcpy(tmpstr,"------");
  return tmpstr;
}
 
nico 发表于: 2001/12/20 10:25am
楼上高水平,我很佩服,多谢了!
 
_cod_aas 发表于: 2001/12/20 04:41pm
1.怎样才能释放你申请的空间???
 在主函数中调用free()??
but how???
 
nico 发表于: 2001/12/20 06:48pm
哈哈!这个问题问得好!如果按taodale的说法,就必须在函数中回收空间了。因为在函数之外的地方是没有这个tmpstr的。
 
Sinbad 发表于: 2001/12/21 01:32pm
char *p;
p=getstr();
{ do something using p }
free(p);
 
lylizm 发表于: 2001/12/21 03:14pm
以下代码在sco下编译通过,结果正确。
#include <stdio.h>
int main(int argc,char **argv)
{
     char *getstr();
     char teststr[255];
     strcpy(teststr,getstr());
     printf("test [%s]\n",teststr);
     exit(0);
 }
 char * getstr(){
 char tmpstr[255];
   
 strcpy(tmpstr,"Hello World!");
 return tmpstr;
 }
 运行显示 test [Hello World!]
 
_cod_aas 发表于: 2001/12/21 05:21pm
我觉得Sinbad的做法不可取,
不过,我也不知道对不对。
那位高手知道的分析一下。
 
nico 发表于: 2001/12/23 01:40pm
include<stdio.h>
char * getstr()
{
      char tmpstr[255];
      strcpy(tmpstr,"------");
      return tmpstr;
}

main()
{
printf("%s\n",getstr());
}
本程序在tc2.0下调试通过。

 
fzheng 发表于: 2001/12/23 03:46pm
nice的程序有一点问题,在编译的时候会有warning: pointer to local 'tmpstr' is
an illegal value.
其实,把程序改一下,就会发现错误。
#include <stdio.h>

char * getstr()
{
     char tmpstr[255];
     strcpy(tmpstr,"------");
     return tmpstr;
}
void anther()
{
char test[255];
strcpy(test,"this is a test");
}
int
main()
{
char *p;
p=getstr();
anther();
printf("%s\n",p);
return 0;

}
结果是this is a test.堆栈中的数据被改变了。

 
redwoods 发表于: 2001/12/24 04:48pm
cod aas,你可不可以解释一下,为什么Sinbad的做法不可取。或者有什么好的办法可以解决这个问题。
我看着Sinbad的方法好像是对的。当然,我是个菜鸟,也不知道究竟对不对,而起现在出差在外,也没有办法试。
 
nico 发表于: 2001/12/25 10:41am
free()仅能释放malloc()申请的空间有关,这一点我在自己家的机器上试过了。
我上面的程序是对的,编译用的是tc2.0, 在win98的dos窗口下通过的,并没有warning。
 
flyfish 发表于: 2001/12/25 12:39pm
我想Sinbad的用法是安全的,
原因就是taodale 的高论。
 
redwoods 发表于: 2001/12/25 01:40pm
nico,你能不能查一下malloc()分配的空间用free()释放的时候有什么要求没有,是不是超出了分配的函数的生存期就不能释放了?
我想如果free()能在函数外释放内存,那还是Sinbad的方法安全。原因见fzheng的程序。
但是还有一个问题,就是如果free()的释放不受限制,那重载的变量该怎么处理?
比如:
void test(void)
{  char * teststr;
 teststr=(char *)malloc(200);
//do something,but not free teststr
return;
}
int main(int argc,char **argv)
{
    char *teststr;    
    test();
    teststr=(char*) malloc(255);
    //do something...
    free(teststr) ;
    exit(0)
}
这会怎么样呢?
 
alonemelive 发表于: 2001/12/25 08:44pm
为什么不把字符串指针作为参数传进函数呢???

 
lchsh 发表于: 2001/12/26 03:36pm
楼上的朋友,你的变量根本就是两个变量,没有重载。
 
nico 发表于: 2001/12/29 11:08am
[quote]
nico,你能不能查一下malloc()分配的空间用free()释放的时候有什么要求没有,是不是超出了分配的函数的生存期就不能释放了?
我想如果free()能在函数外释放内存,那还是Sinbad的方法安全。原因见fzheng的程序。
但是还有一个问题,就是如果free()的释放不受限制,那重载的变量该怎么处理?
比如:
void test(void)
{  char * teststr;
teststr=(char *)malloc(200);
//do something,but not free teststr
return;
}
int main(int argc,char **argv)
{
   char *teststr;    
   test();
   teststr=(char*) malloc(255);
   //do something...
   free(teststr) ;
   exit(0)
}
这会怎么样呢?
[/quote]

free()仅释放main()中申请的空间。
但如果你试一下的话会发现在主函数中可以用函数test()中的teststr,也就是说free()掉main()中的teststr后,再次调用teststr后可以打出它的值。这是因为你设了两个相同的变量。不过,具体为什么会出现这种现象,用taodale的原理无法解释。我也不懂。

 
fanyan1999 发表于: 2001/12/29 11:39am
我建议把程序改成这样:
void getstr(char *tmpstr){
  strcpy(tmpstr,"------");
}
在函数中返回字符串的方法不安全,因为函数结束时为该函数分配的内存都会被释放掉。fzheng的话很有道理。佩服佩服!!!

 
alai 发表于: 2002/08/10 10:17am
这确是一个简单的问题,没有一个标准答案,Sinbad的方法也是对的,但更通常的做法是将tmpstr定义为静态的,这样它的内存不会在getstr()退出时被释放,也不需要在外面用free()释放,不过第二次调用getstr()会覆盖前次的返回值。这种方法是在许多标准C函数中被使用。

char * getstr(){
  static char tmpstr[255];
 
  strcpy(tmpstr,"------");
  return tmpstr;
}

 
netstorm 发表于: 2002/08/10 11:42am
[quote][b]下面引用由[u]lylizm[/u]在 [i]2001/12/21 03:14pm[/i] 发表的内容:[/b]
以下代码在sco下编译通过,结果正确。
以下代码在sco下编译通过,结果正确。
#include <stdio.h>
int main(int argc,char **argv)
{
    char *getstr();
    char teststr[255];
    strcpy(teststr,getstr());
    printf("test [%s]\n",teststr);
    exit(0);
}
char * getstr(){
char tmpstr[255];
 
strcpy(tmpstr,"Hello World!");
return tmpstr;
}
运行显示 test [Hello World!]

[/quote]

把 char tmpstr[255] 改成 char tmpstr[13],运行你的程序会出什么问题??

如果定义成 static char tmpstr[13]呢?? :)

 
aegis 发表于: 2002/08/10 12:09pm
nico 你的程序有问题,不能保证正确性
free () 能释放 malloc () 得到的内存。getstr () 函数不知是不是标准函数
我一般这样使用
c++:

char * p = new char [ 255 ];
/* do some worke with p */
delete p;

c:

char * p;
if ( null == (p = malloc ( 255 )) ) return ErrorNoMem;
/* do some work with p */
free ( * p );

free () 可以在任何函数中使用,不必和 malloc 在同一作用域
但要注意 指针变量 的作用域问题;

 
flw 发表于: 2002/08/12 09:06pm
我认为诸位的方法都不好.其实还有一种方法,那就是将 char tmpstr[255]; 声明写做: static char tmpstr[255]; 即可.不过这样将加长"静态存储区"的长度, 所以更科学的方法应该是将函数声明改成 char *getstr( char *tmpstr ); 即 tmpstr 由形式参数传入, 至于其空间嘛, 就不是 getstr 的责任了, 完全可以由外部分配. 另外我点评一下 taodale
的做法: 这样做虽然可以,但是习惯不好,降低了函数模块的"内聚性",谁上的厕所谁就冲马桶嘛! 另外, lylizm 的做法依赖于编译器, 本来嘛, 局部变量是存在于堆栈中的,那么对它的指针引用在堆栈不发生变化的前提下应该不会有问题, 但是,这不是 C 的语法所要求的, 所以并不可行/可靠, 换句话说, 这样做有三种结果: 1. 编译不能通过(因为编译器要求太严), 2, 内容不正确(原因比较复杂), 3, 正确. 事实上, 我在 SCO Unix 5.05 下就发现有这样的情况: (参见 lylizm 的例子) 在函数外部输出的内容为: [Hello World] 注意, 丢失了最后一个字符, 我曾经把 "电话银行" 中客户输入的密码就丢失了一位, 最后才查出是这个原因.
   总之, 1,当 tmpstr 较短时, 宜采用类似 static char tmpstr[6]; 的写法; 2, 当 tmpstr 较长时, 宜采用外部分配, 外部回收, getstr() 处理指针的方法.
 
flw 发表于: 2002/08/12 09:13pm
不好意思, 我发上面这个帖子的时候没有看见第二页上各位大侠的帖子.所以有些话不太得体.
 
badeager 发表于: 2002/08/31 01:19pm
#include <stdio.h>
char *getstr(char *tmpstr)
{
 //   char tmpstr[255];
    strcpy(tmpstr,"------");
    return tmpstr;
}
int
main()
{
char *p;
p = (char *)malloc(255);
p=getstr(p);

printf("%s\n",p);
return 0;

}

 
sonice 发表于: 2002/09/03 05:02pm
[quote][b]下面引用由[u]nico[/u]在 [i]2001/12/23 01:40pm[/i] 发表的内容:[/b]
include<stdio.h>
char * getstr()
{
      char tmpstr;
...
[/quote]

char str[255] 申明的变量在 stack 中, 函数返回后就不确定了。编译成功只是巧合。malloc 出来的空间是在 heap 中,在进程的生存期都有效。所以 sinbad 和  badeager 的方法是最安全的。

 
tianzhushan 发表于: 2002/09/08 10:35am
继续!
 
tianzhushan 发表于: 2002/09/08 10:42am
这个函数的为什么没有输出为乱码?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
char *getmemory(void)
{
 char p[]="hello world";
 return p;
}
void test(void)
{
 char str[100];
 int i=0,len;
 strcpy(str,getmemory());
 printf("the str is:%s\n",str);
}

main()
{
 test();
}

 
sonice 发表于: 2002/09/08 10:39pm
楼上的程序没有出错是巧合。解释如下:
char p[] = "hello world"; --> p 的空间在栈中,函数返回后栈空间就是自由空间了,可能被其他函数使用。你的函数没有出错是因为没有其他函数使用 p 所在的空间,但不能保证每次都这样。简单的程序不能说明问题,也证明不了什么。malloc 或者 new 出来的空间是在堆中,堆中声明的空间如果你不释放(free or delete),在整个进程的生存期都不会被改变。

btw: malloc 系列函数中有一个可以强迫在栈中声明空间,这种空间不用去释放。

 
fred08 发表于: 2002/10/11 10:20am
我看了各位的解决方案,很多都是可行的,但我认为还是flw的最好最全面,因为这样比较安全,不会留下bug。
 
dongdongwx 发表于: 2002/10/11 11:36am
能不用free的时候,最好不用她,不安全
给函数加一个字符串指针变量,好一点
 
aegis 发表于: 2002/10/13 02:55am
看来笨蛋不少

free 当然可释放 malloc 获得的内存了,不论是在哪个函数中申请的

你编译过去,“调试通过”,只不过是凑巧罢了,程序太简单了

读书去吧

 
redgoat 发表于: 2002/10/14 02:53pm
[这个贴子最后由redgoat在 2002/10/14 02:54pm 编辑]

sonice,你没搞错吧??!! 应该是静态内存才对,而并不是在栈中
 
flw 发表于: 2002/10/24 06:26pm
[quote][b]下面引用由[u]aegis[/u]在 [i]2002/10/13 02:55am[/i] 发表的内容:[/b]
看来笨蛋不少
free 当然可释放 malloc 获得的内存了,不论是在哪个函数中申请的
你编译过去,“调试通过”,只不过是凑巧罢了,程序太简单了
读书去吧
[/quote]
我同意这位仁兄的观点,我认为许多同学们还是应该把多读些语法方面的书,把语法重视起来,不要象我在别的地方听到的一样,竟然说潭老师的《C程序设计》罗罗嗦嗦,“没有实用价值”!
 
紫竹 发表于: 2002/10/27 02:32am
   原因是某一函数中的非指针变量是存放于栈中的,在退出时全部释放,因此这些局部变量也就没其存在的基础。但返回的指针变量可以是局部指针变量。
 
lljsun 发表于: 2002/10/29 10:40am
没有一点问题啊,我在sco unix上顺利编译运行,源代码一点没变。我觉得跟内存分配无关
char * getstr(){
  char tmpstr[255];  
  strcpy(tmpstr,"------");
  return tmpstr;
}
main(int argc,char argv[])
{
char t[200];
strcpy(t,getstr());
printf("getstr()  :%s\n",t);
}
 
stonepine 发表于: 2002/10/29 10:57am
taodale说得对,malloc()出来的内存区如果程序没有通过free()释放,会一直存在,即使程序退出,也会继续存在,只是此时变成不可访问的无用内存了。而临时变量以及数组则有它严格的作用域,由编译器分配和释放内存,redwoods在上面的帖子中没有注意变量的作用域问题,应该写成如下代码:
void test(void)
{  
char * teststr;
teststr= malloc(200);
//do something,but not free teststr
return teststr;
}
int main(void)
{
   char *teststr;    
   teststr = test();
   if ( teststr ) free(teststr) ;
   exit(0);
}


 
xiangzg 发表于: 2002/10/29 11:41am
多了解一下c和c++编译系统,如果想做个好的程序员!
 
zglcl008 发表于: 2002/10/29 08:02pm
free()能在函数外释放内存
 
cloudqin 发表于: 2003/01/07 04:30pm
这个问题太弱智了!不知道是不是刚写程序的菜菜!
在函数内定义的char数组是属于堆栈内的,函数退出就被释放了,简单点可以这样:
void getstr(char* tmpstr){
 
  strcpy(tmpstr,"------");
}

mani()
{
  char tmpstr[255] = {0};
  getstr(tmpstr);
/////do u anything////
  printf("%s", tmpstr);

}

 
cloudqin 发表于: 2003/01/07 05:08pm
fff
 
晴天羽 发表于: 2003/01/08 11:23am
最好的用法还是用变量传递。
void  getstr(char *p, int inlen)
{
  p = (char *)malloc(inlen);
   strcpy(p,"------");
   return p;
}
 
taige 发表于: 2003/01/08 03:45pm
楼主的做法肯定是不对的,
即使在小的程序中,
表面上运行没有问题(楼上一些仁兄所列),
但是大程序中就不敢肯定没有问题,
实际上这应该算程序的一个大BUG。

当然在函数里面进行malloc()内存动态分配不会有问题,
但是要记得调用free()。
free的参数只是一个内存指针,
只要它指向的内存空间由malloc分配且未被free,
不用管在哪个函数里面由malloc分配的。

用static定义函数内的字符串变量也可以,
这样的话函数返回的时候,
该变量就不会释放,也就不会有问题。

当然,可以把一个字符串作为参数传入函数,
但是“晴天羽”的做法 :emn20:
推荐在调用函数前定义好足够长的字符串变量。

个人觉得还是用static定义变量最简单 :em11:

 
 

Copyright © ChinaUnix.net  *  转载请注明出处及作者