C++中指针和引用区别

 

一、概念

指针

        对于一个类型T,T*就是指向T的指针类型,也即一个T*类型的变量能够保存一个T对象的地址,而类型T是可以加一些限定词的,如const、volatile等等。

       见下图,所示指针的含义:

引用

       引用是一个对象的别名,主要用于函数参数和返回值类型,符号T&表示T类型的引用。

       见下图,所示引用的含义:

二、指针和引用的区别

是否需初始化

       首先,引用不可以为空,但指针可以为空。

       前面也说过了引用是对象的别名,引用为空——对象都不存在,怎么可能有别名!故定义一个引用的时候,必须初始化,而指针可以不用。

       因此如果你有一个变量是用于指向另一个对象,但是它可能为空,这时你应该使用指针;如果变量总是指向一个对象,你的设计不允许变量为空,这时你应该使用引用。

如下代码中,如果定义一个引用变量,不初始化的话连编译都通不过:

#include<iostream>
using namespace std;
int main()
{
	int i = 0;
	//int& ref;		//IntelliSense:  引用 变量 "ref" 需要初始值设定项
	return 0;
}

是否可以改变指向

       引用不可以改变指向;但是指针可以改变指向,而指向其它对象。

       说明:虽然引用不可以改变指向,但是可以改变初始化对象的内容。

       例如就++操作而言,对引用的操作直接反应到所指向的对象,而不是改变指向;而对指针的操作,会使指针指向下一个对象,而不是改变所指对象的内容。

如下代码:

#include<iostream>
using namespace std;
int main()
{
	int i = 10;
	int& ref = i;
	ref++;
	cout << "i=" << i << endl;
	cout << "ref=" << ref << endl;
	int j = 20;
	ref = j;
	ref++;
	cout << "i=" << i << endl;
	cout << "ref=" << ref << endl;
	cout << "j=" << j << endl;
	system("pause");
	return 0;
}

执行结果为:

i=11
ref=11
i=21
ref=21
j=20

       对ref的++操作是直接反应到所指变量之上,对引用变量ref重新赋值”ref=j”,并不会改变ref的指向,它仍然指向的是i,而不是j。理所当然,这时对ref进行++操作不会影响到j。

       而对指针的++操作是在地址上++。

大小

       引用的大小是所指向的变量的大小,因为引用只是一个别名而已;指针是指针本身的大小,4个字节。

如下代码:

#include<iostream>
#include<string>
using namespace std;
int main()
{
	string str = "12345678";
	string ref = str;
	string* pointer = &str;
	cout << "ref: " << ref << "\tpointer:" << *pointer << endl;
	cout << "sizeof(ref):" << sizeof(ref) << "\tsizeof(pointer):" << sizeof(pointer) << endl;
	system("pause");
	return 0;
}

执行结果为:

ref: 12345678   pointer:12345678
sizeof(ref):28  sizeof(pointer):4

       从上面也可以看出:引用比指针使用起来形式上更为美观,使用引用指向的内容时可以之间用引用变量名,而不像指针一样要使用*;定义引用的时候也不用像指针一样使用&取址。

安全性

       引用比指针更安全。由于不存在空引用,并且引用一旦被初始化为指向一个对象,它就不能被改变为另一个对象的引用,因此引用很安全。对于指针来说,它可以随时指向别的对象,并且可以不被初始化,或为NULL,所以不安全。const 指针虽然不能改变指向,但仍然存在空指针,并且有可能产生野指针(即多个指针指向一块内存,free掉一个指针之后,别的指针就成了野指针)。
       总而言之,言而总之,它们的这些差别都可以归结为”指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名,引用不改变指向。

三、const问题

常量指针VS常量引用

常量指针

        指向常量的指针,在指针定义语句的类型前加const,表示指向的对象是常量。

如下代码:

#include<iostream>
using namespace std;
int main()
{
	int i = 0, j = 1;
	const int* pointer = &i;
	pointer = &j;
	//*pointer = 1;	//IntelliSense:  表达式必须是可修改的左值
	j = 2;
	cout << *pointer << endl;
	system("pause");
	return 0;
}

执行结果为:

2

        定义指向常量的指针只限制指针的间接访问操作,而不能规定指针指向的值本身的操作规定性。即:通过指针不能修改变量值,但通过变量名可以直接修改变量值。

       可以修改指针的指向。

常量引用

       指向常量的引用,在引用定义语句的类型前加const,表示指向的对象是常量。

如下代码:

#include<iostream>
using namespace std;
int main()
{
	int i = 0;
	const int& ref = i;
	//ref = 1;	//IntelliSense:  表达式必须是可修改的左值
	i = 2;
	cout << ref << endl;
	system("pause");
	return 0;
}

执行结果为:

2

       也跟指针一样不能利用引用对指向的变量进行重新赋值操作,但可以通过变量名直接进行赋值。不能修改引用指向(固有特性)。

指针常量VS引用常量

       在指针定义语句的指针名前加const,表示指针本身是常量。

如下代码:

#include<iostream>
using namespace std;
int main()
{
	int i = 0, j = 1;
	int* const pointer = &i;
	//pointer = &j;	//IntelliSense:  表达式必须是可修改的左值
	*pointer = 2;
	cout << *pointer << endl;
	system("pause");
	return 0;
}

执行结果为:

2

       不可以改变指针指向,但是可以通过指针间接改变变量值。

       在定义指针常量时必须初始化

       不能改变指向是引用天生具来的属性,不用再引用指针定义语句的引用名前加const。

常量指针常量VS常量引用常量

       常量指针常量:指向常量的指针常量,可以定义一个指向常量的指针常量,它必须在定义时初始化。常量指针常量定义”const int* const pointer=&c”告诉编译器,pointer和*pointer都是常量,他们都不能作为左值进行操作。

       而就不存在所谓的”常量引用常量”,因为跟上面讲的一样引用变量就是引用常量。C++不区分变量的const引用和const变量的引用。程序决不能给引用本身重新赋值,使他指向另一个变量,因此引用总是const的。如果对引用应用关键字const,起作用就是使其目标称为const变量。

       总结:有一个规则可以很好的区分const是修饰指针,还是修饰指针指向的数据。如果const出现在星号的左边,指针指向的数据为常量;如果const出现在右边,指针本身为常量。

       引用本身与天俱来就是常量,即不可以改变指向。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

使君杭千秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值