威盛的一道笔试题

威盛的一道笔试题

silver6 | 02 十一月, 2005 09:20

 

#include <stdio.h>
char *returnStr()
{
char p[]="hello world!";
return p;
}
int main()
{
char *str;
str=returnStr();

printf("%sn",str);
}
问上述的输出是什么?
还有就是我把上述函数稍改一下
#include <stdio.h>
char *returnStr()
{
char *p="hello world!";
return p;
}
int main()
{
char *str;
str=returnStr();

printf("%sn",str);
}
这个输出又是什么?各是什么原因呢

 

 

 

 

char p[]="hello world!";
p指向一个局部的数组地址,分配在栈中。
char *p="hello world!";
p指向一个字面常量。字面常量分配在哪里俺就不知道了。总之不会是局部的。

所以:
第一个指向的是个已被释放的内存,不会输出hello world!,要出错的吧
第二个输出的是: hello world!

 

 

 

1: 一切皆有可能
char[]为局部变量,returnStr结束后可能被覆盖
2: hello world!
"hello world!"是data segment的数据,不会改

 

 

 

第一种情况输出的应该是乱码,第二种情况输出的是hello world!。
前者char p[]这行的p是局部变量,由于是数组类型返回p后,p被销毁,所以就会输出乱码。
后者char *p这行的p虽然也是局部变量,但由于p是指针类型的,所以返回的p在赋予main里的str时会重新申请一块内存来存放数据,最后显示也就正常了。

 

 

 

可以用这段代码比较看一下:
#include <stdio.h>
char r[]="1234567890";
char *s1()
{
char p[]="1234567890";
printf("--------------------n");
printf("in s1 p: %dn",r);
printf("--------------------n");
return r;
}

char *s2()
{
char *q="1234567890";
printf("--------------------n");
printf("in s2 q: %dn",q);
printf("--------------------n");
return q;
}
int main()
{
char *t1,*t2;
t1=s1();
t2=s2();
printf("--------------------n");
printf("in mainn");
printf("p: %d, q: %dn",t1,t2);
printf("--------------------n");

printf("%sn",t1);
printf("%sn",t2);

}

 

 

 

不好意思楼上r的地方没有改回来,应该是下面的:
#include <stdio.h>
char *s1()
{
char p[]="1234567890";
printf("--------------------n");
printf("in s1 p: %dn",p);
printf("--------------------n");
return p;
}

char *s2()
{
char *q="1234567890";
printf("--------------------n");
printf("in s2 q: %dn",q);
printf("--------------------n");
return q;
}
int main()
{
char *t1,*t2;
t1=s1();
t2=s2();
printf("--------------------n");
printf("in mainn");
printf("p: %d, q: %dn",t1,t2);
printf("--------------------n");

printf("%sn",t1);
printf("%sn",t2);

}

 

 

 

这个问题在林锐的高质量C++/C编程指南上有,内容如下:
http://www.cnns.net/ref/cppguide.htm
所以回答是:
1、报错。p是局部变量,保存在栈里,函数结束后p已经销毁,成为wild pointer。
2、hello world!因为p是一个指向字符串常量的指针,字符串常量保存在.data(已定义的全局变量)里,函数返回时那个指针地址还是有效的。
当然,你如果想查看一下,上面的两个程序指针指向不同的地方,你可以打印出指针的地址。
printf("%p",p);还有,你如果想直接打印出字符串常量所存放的地址,你可以用这个
printf("%p","Hello world!");想知道为什么吗?c primer里面有,因为"Hello world!"就可以表示指向这个字符串常量的指针了!

 

 

 

关于char p[] = “Hello world!”的讨论,已经很正确了。
那么现在我们来讨论 char *p = “Hello world!”的问题。
Char * fun()
{
char *p = “Hello world!”
return p;
}
Main ()
{
Char * p = NULL;
P = fun();
Cout<< p;
Cout<<&p;
}
我们发现其可以完全打印出hello world,并且打印其地址,并且不会有任何问题。到底是什么原因哪?
我们在main中在重新定义一个char变量*p1
*p1 = fun();
打印出*p1的值和地址,我们惊奇的发现p1和p的地址相同。不幸的是我们定义*p2=fun(),其打印出的地址和前两次也相同。所以说“返回的p在赋予main里的p时会重新申请一块内存来存放数据,最后显示也就正常了”是不正确的,如果是这样应该其内存是不相同的。但是这好像还是不能完全说明问题,问题是“hello world”数据到底放在哪里了那?
我们知道程序内存主要分三部分:静态存储区,堆,栈,那么到底放在那个上面了那?
我们在定义一个函数
Char * fun2()
{
char *p = “Hello world!”
return p;
}
此时和在main调用fun()一样,分别定义*p,*p1,*p2,分别调用fun2();打印其结果和地址,你会吃惊的发现此时的地址居然和调用fun()函数的地址完全相同,我没有吓唬你。是真的完全一样。至此我们可以明白一点原来fun()和fun2()中的地址完全相同,也就是说他们共同应用的是一块地址,能够在整个程序运行过程中共同占有一块地址的。肯定放在静态存储区上,至此问题明了。
Char *p = “Hello World!”数据放在静态存储区上,为了我们说明问题,我们在多做几个实验。
我们定义全局变量char *p1= “Hello World!”,那么这次我们分别调用不同的指针指向fun(),fun2(),全局*p,在打印其地址。看到地址我们有吃惊,居然地址又是完全相同,到底怎么回事?
原因很简单,我们在定义这些变量的时候,编译器会根据我们定义的值在静态存储区开辟地址,保存内容,简单的把地址返回给不同的地址指针而已。如果你还是不相信,你可以把全局变量*p1的值更改为其他字符串,你会发现*p1的地址和fun(),fun2()的地址是相邻的。我们知道全局变量肯定放在静态存储区,所以现在我们更加肯发定fun,fun2内的char *p= “Hello World!”数据放在静态存储区。
现在完了,没有。
我们在main中定义*p,指向fun();

Char *p = null;//良好的习惯
p= fun();
p[0] = ‘U’;//我的意图很明显就是想变成“Uello World!”
编译通过,高兴。
运行出错,追踪,p[0] = ‘U’;在这句出错,运行错误说明不能更改p[0]的值。哦,至此我们明白了,原来编译器是这样给我们作的
const char temp[] = “Hello World!”;
char *p1 = temp;
为了验证编译器是否这样做我们定义
全局变量
char pp[] = “Hello World!”;
在main中调用char *p = pp;
p[0] = ‘U’;
打印p,终于按我们的要求打印出 Uello World!
再看看p1和pp的地址,发现不相同,但是地址相邻。为什么?
const对象和非const对象内容当然不相同了!
至此我们总结如下:
我们在函数,全局内定义的char *p = “Hello World!”;编译器都会为我们作为全局变量定义。伪代码如下
const char temp[] = “Hello World!”;
char *p1 = temp;
任何调用“Hello World!”只是返回temp的一个const指针。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值