返回指针的函数

函数返回指针

2011-10-09 13:26 天成天下  |  分类:C/C++  |  浏览4568次
我有一个程序是这样的:
int main()
{
	int *p;
	int i;
	int*fun(void);
	p=fun();
	for(i=0;i<3;i++)
	{
		printf("%d\n",*p);
		p++;
	    
	}
	
	return 0;
};
int* fun(void)
{
	static int str[]={1,2,3,4,5};
	 int*q=str;
	return q;
}
我想问一下,除了将str定义为静态区以及用malloc这样的方法外,还有什么好的方法,同时也想问一下如果我改成
int main()
{
	char *p;

	char*fun(void);
	p=fun();
	
	printf("%s\n",p);

	return 0;
};
char * fun(void)
{
	char *str="hello";

	return str;
}
为什么能输出准确值,函数返回指针有哪些方法。
使用字符数组时,就能返回正确值
int main()
{
	char *p;
	char *fun(void);
	p=fun();
	printf("%c",p[2]);
	return 0;
};

char* fun(void)
{
	char str[]={'a','b','c'};
	return str;
}
但若将str[]改成str[]="hello"却不行。
2011-10-09 14:00 提问者采纳
您的后一个例子中,虽然str是在动态变量区,而该动态变量是局部的,函数结束时不保留的。
但是,字符串"hello"不是变量,而是一个常量编译程序在处理这种常量时,通常把它放在了常量区中。而常量区则是始终存在的。
后一个例子中函数fun的返回值就是一个指向这种常量区的指针。

函数返回指针,要使主程序可以使用这个指针来访问有意义的数据,关键就是要保证在使用这个指针值的时候,该指针所指向的地方的数据仍然有意义。
除了您所说的:用静态区以及用malloc这样的方法外,还有就是第二个例子里的:用常量区。再另外,还可以用全局变量,也就是说返回的指针是指向全局变量的。

还有,如果指针是指向函数的指针,那么这个指针就是指向程序代码区的。这也是一种应用的情况。

另外,如果明白了它的原理,程序员还可以发明出一些其他灵活的使用方法,当然,那都属于“怪”方法,一般不提倡的。 
【总结】
常规程序中,函数返回的指针通常应该是:
(1)指向静态(static)变量;
(2)指向专门申请分配的(如用malloc)空间;
(3)指向常量区(如指向字符串"hello");
(4)指向全局变量;
(5)指向程序代码区(如指向函数的指针)。 
除这5项以外,其它怪技巧不提倡。
追问
这里我还是没太明白,比如:
int main()
{
	int a,b;
	int max;
	int fun (int a,int b);	
	scanf("%d%d",&a,&b);
	max=fun (a,b);
	printf("\n%d\n",max);
	return 0;
};
int fun(int a,int b)
{
	int max;
	if(a>b)
		max=a;
	else 
		max=b;
	return max;
}
在这个程序,为什么在fun()函数中就能返回max,按照动态存储原理,在fun结束时,就max就被释放了,不能再返回值了。但事实却不是这样。
回答
这个例子中,返回的不是变量max的地址,返回的是它的值。
return后面的东西,看做一个表达式,返回的是这个表达式的值。
例如,入口如果a是3,b是5,则此时(执行return语句时)max里面存的是5。而return语句的功能就是把max里面的5取出来,放到“返回值寄存器”中。
主程序是从“返回值寄存器”得到这个5的(此时max变量已经不存在了)。

你前面的第二个例子中,同样,指针变量str在函数结束后已经不存在了。但是在return语句中,把指针变量str里面的值(等于字符串"hello"存放处的地址)送到“返回值寄存器”中了。
动态变量str不存在了,但常量区中的字符串"hello"还存在。主程序根据返回的地址就可以找到该字符串。
追问
返回的是值,这个我明白了,但还是有点不明白的是:
int main()
{
	char *p;
	char *fun(void);
	p=fun();
	printf("%x\n",p);
	printf("%s\n",p);
	return 0;
}

char* fun(void)
{
//	char str[]={'a','b','c','d','e','f','\0'};
	char str[]="hello";
	printf("%x\n",str);
	return str;
}
返回的也是str的地址,从结果来看p和str的值相等,但为什么准确,我的qq是121814322,谢谢加我,希望继续请教。
回答
char str[]="hello"; 和 char *str="hello"; 不一样。

char str[]="hello"; 是在动态变量区中开辟了可以容纳6个字符的数组,数组名叫str。同时将字符串"hello"(原存放于常数空间)拷贝到这个数组空间中去作为数组的初始化值。
此时若执行return str; 其中的str是数组名。C语言规定,表达式中如果是数组名,则该表达式的值就等于这个数组的地址。所以返回的是这个数组的地址,请注意:并不是字符串常量"hello"的地址!而函数结束时,虽然常数空间并不破坏,但这个数组空间是破坏了的,而你返回的却不是常数空间里的地址而正是已经破坏了的数组的地址。

而char *str="hello"; 是在动态变量区中开辟了一个可以存放一个指针值的变量,名叫str。同时将原存放于常数空间的字符串"hello"的地址赋给这个指针变量作为初始值。
此时若执行return str; 其中的str是指针变量名。C语言规定,表达式中如果是变量名,则该表达式的值就等于这个变量的值。所以返回的是变量str的值,而变量str的值就等于字符串常量"hello"的地址。而函数结束时,变量str破坏了的,但常数空间中的字符串并不破坏。主程序根据返回的地址就可以找到该字符串。
【再补充】
您最后的【问题补充】中的新例子,用了char str[]={'a','b','c'};据我所知,应该是不行的。

您之所以说试验了能行,有两种可能的原因:
(1)有可能函数返回后虽然数组str的空间已经被释放了,但暂时该空间还没有被新的内容完全覆盖冲掉,所以您用p[2]访问的时候那个位置里原来的字符还在。
(2)有可能具体某个编译程序对这类数组做了特殊处理(例如强行把它做成了静态的)。按标准,具体的编译程序应该保证符合标准的程序能正确运行,但“不符合标准”的程序并不一定要“不能运行”。如果某个编译程序放宽标准使得某些不合标准的程序也出了正确的结果,这个编译程序不算不标准。

如果是第一种原因,那么程序上下文改一改,就可能不成立了;如果是第二个原因,那么换一个C版本,就可能不成立了。
提问者评价
非常感谢,现在终于明白了。
评论(7) | 25
按默认排序|按时间排序

其他2条回答

2011-10-09 13:34 tuxtoken |六级
这个有问题,因为局部变量只在作用域内工作。
char * fun(void)
{
	char *str="hello";

	return str;
}
静态和malloc已经够了,还有可以使用STL里的容器等,让他们帮你存取。
评论 | 0
2011-10-09 13:42 0800840225 |四级
函数内的变量,没有关键字static修饰的变量的生命周期只在本函数内,函数结束后变量自动销毁。当返回为指针的时候需要特别注意,因为函数结束后指针所指向的地址依然存在,但是该地址可以被其他程序修改,里面的内容就不确定了,有可能后面的操作会继续用到这块地址,有可能不会用到,所以会出现时对时错的情况,如果需要返回一个指针而又不出错的话只能调用内存申请函数。
评论(1) | 2
今天你做任务了没?
全部任务

帮助 | 意见反馈 | 投诉举报 | 知道协议 | 加入我们

©2013Baidu  使用百度前必读 | 百度知道开放平台

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值