指针和引用看上去完全不同,但它们似乎具有相同的功能。先看一个小例子,了解下究竟编译器对他们做了什么处理。
int main()
{
int i = 3;
int *p = &i;
return 0;
}
我们生成它的汇编代码,主要部分为:
main:
.LFB2:
pushl %ebp
.LCFI0:
movl %esp, %ebp
.LCFI1:
subl $8, %esp
.LCFI2:
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
subl %eax, %esp
movl $3, -4(%ebp) //i初始化
leal -4(%ebp), %eax //加载i的地址到寄存器eax
movl %eax, -8(%ebp) //把i的地址赋值给p
movl $0, %eax
leave
ret
然后把int *p = &i改成 int &p=i;再生成汇编代码,发现和上面是一样的(在Linux下diff file1 file2)。那就可以这样认为,对于编译器指针和引用是没有任何区别的。那什么时候用指针,什么时候用引用,在使用中又有什么不同。
1. 指针可以不初始化,但是引用不行,引用相当于别名,不可能给一个不存在的事物取个歪名吧。
int *p; //right
int & r; //error
延伸一下,如
int *parr[10]; //right
int &rarr[10]; //wrong
可以定义指针数组,但不可以定义引用数组,这很好理解,引用必须初始化。看下面
int k[10] = {1,...,10};
int (*parr)[10] = &k; //right
int (&rarr)[10] = k; //right
可以定义数组指针去指向k数组,引用也可以。
2. 指针在使用之前需要检测是否为空,而引用不需要。
if(NULL!=p) {
...
}
3. 当对指针和引用进行操作时,他们表现出不同的特性。
p++; //p自增,指向下一个位置
r++; //是对引用所指的对象进行自增操作。
p=&j; //p指向另一个变量j
r=j;//把j的值赋值给i
4. 对于引用需要养成好习惯,尽量对非指针变量采用引用,呵呵,这纯属个人观点。像下面这样使用,合法但是却造成未定义的行为,这是非常危险的行为,要尽量避免这样的陷阱。
int * p = NULL;
int& rc = *p;
当指向一个对象而又不想改变指向时,用引用吧。