[C++面试题]之指针与引用(1)

     指针是C系语言的特色。指针是C++提供的一种颇具特色的数据类型,允许直接获取和操纵数据地址,实现动态存储分配。

     指针问题,包括常量指针、数组指针、函数指针、this指针、指针传值、指向指针的指针等,这些问题也是各大公司常备考点,下面让我们一起学习其中的重点与难点。

1、指针与引用的区别?

答案:

(1)非空区别。在任何情况下都不能使用指向空值的引用。因此如果你使用一个变量并让它指向一个对象,但是该变量在某些时候也可能不指向任何对象,这时你应该把变量声明为指针,因为这样你可以赋空值给该变量。相反,如果变量肯定指向一个对象,例如你的设计不允许变量为空,这时你就可以把变量声明为引用。不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针要高。

(2)合法性区别。在使用引用之前不需要测试它的合法性。相反,指针则应该总是被测试,防止其为空。

(3)可修改区别。指针与引用的另一个重要的区别是指针可以被重新赋值以指向另一个不同对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变,但是指定的对象其内容可以改变。

 

2、下面5个函数哪个能成功进行两个数的交换?

#include<iostream>
using namespace std;

void swap1(int p,int q)
{
	int temp;
	temp=p;
	p=q;
	q=temp;
}

void swap2(int *p,int *q)
{
	int *temp;
	*temp=*p;
	*p=*q;
	*q=*temp;
}

void swap3(int *p,int *q)
{
	int *temp;
	temp=p;
	p=q;
	q=temp;
}

void swap4(int *p,int *q)
{
	int temp;
	temp=*p;
	*p=*q;
	*q=temp;
}

void swap5(int &p,int &q)
{
	int temp;
	temp=p;
	p=q;
	q=temp;
}

int main ()
{
	int a=1,b=2;
	//swap1(a,b);
	//swap2(&a,&b);
	//swap3(&a,&b);
	//swap4(&a,&b);
	//swap5(a,b);
	cout << "a:"<< a <<endl;
	cout << "b:"<< b <<endl;

	return 0;
}

解析:这道题考察的是参数传递、值传递、指针传递(地址传递)和引用传递。

     swap1传递的是值的副本,在函数中只是修改了形参p、q(实际是a、b的一个拷贝),p、q的值确实交换了,但是它们是局部变量,不会影响到主函数a和 b 。当函数swap1生命周期结束时,p、q所在的栈也就被删除了。

     swap2传递的是一个地址进去,在函数体内的形参*p、*q是指向实际的参数a、b地址的两个指针。

     这里要注意:

             int *temp;

             *temp=*p;

     是不符合逻辑的,int *temp新建了一个指针(但是没分配内存)。*temp=*p不是指向而是拷贝。把*p所指向的内存的值(也就是a 的值)拷贝到*temp所指向内存里了。但是int *temp不是不分配内存吗?的确不分配,于是系统在拷贝时临时给了一个随机地址,让它存值。分配的随机地址是个“意外”,且函数结束后不回收,造成内存泄漏。

     swap3传递的是一个地址,在函数体内的参数*p、*q是指向实际参数a、b地址的两个指针。

     这里要注意:

             int *temp;

             temp=p;

     int *temp新建了一个指针(但是没分配内存)。temp=p是指向而不是拷贝。temp指向了*p所指向的地址(也就是a )。而代码:

             int *temp;

             q=temp;

     但是函数swap3不能实现两数的交换,这是因为函数体内只是指针的变化,而对地址中的值却没有变化。

     swap4可以实现两数的交换,因为它修改的是指针所指向地址中的值。

     swap5函数与swap4相似,是一个引用传递,修改的结果直接影响实参。

答案:

swap4 函数和 swap5 函数。

 

3、这个函数有什么问题?该如何修改?

char *strA()
{
	char str[] = "hello world";
	return str;
}

 

解析:这个str里存在的地址是函数strA栈里“hello world”的首地址。函数调用完成,栈帧恢复调用strA之前的状态,临时空间被重置,堆栈“回缩”,strA栈帧不再属于应该访问的范围。这段程序可以正确输出结果,但是这种访问方法违背了函数的栈帧机制。

      但是只要另外一个函数调用的话,你就会发现,这种方式的不合理及危险性。

      如果想获得正确的函数,改成下面这样就可以:

char *strA()
{
	char *str = "hello world";
	return str;
}

      首先要搞清楚char *str 和 char str[] :

char str[] = "hello world";

是分配一个局部数组。局部数组是局部变量,它所对应的是内存中的栈。局部变量的生命周期结束后该变量不存在了。

char *str = "hello world";

 

是指向了常量区的字符串,位于静态存储区,它在程序生命期内恒定不变,所以字符串还在。无论什么时候调用 strA,它返回的始终是同一个“只读”的内存块。

      另外想要修改,也可以这样:

char *strA()
{
	static char str[] = "hello world";
	return str;
}

      通过static开辟一段静态存贮空间。

答案:

因为这个函数返回的是局部变量的地址,当调用这个函数后,这个局部变量str就释放了,所以返回的结果是不确定的且不安全,随时都有被收回的可能。

 

对于指针与引用这部分还有一些内容,都是比较难的,还需要花点时间研究研究,最近这几天也比较忙,剩下的会给你们的,嗯,今天就这点了……

posted @ 2011-11-03 18:39  it笨笨  阅读(6777)  评论(7编辑  收藏  举报