合类型是指基于其他类型定义的类型。C++语言有几种符合类型,引用和指针
1、引用。(左值引用)
引用为对象起了另外一个名字,引用类型另外一种类型。通过声明符写成&d的形式来定义引用类型。其中d是生命的变量名。
int a=1024;
int &val=a;//val指向a(是a的另一个名字)
int &cal;//报错,引用必须被初始化
一般在初始化变量时,初始值会被拷贝到新建的对象中。然而定义引用时,程序把引用和他的初始值绑定在一起,而不是将初始值拷贝给引用。一旦初始化完成,引用将和它的初始值对象一直绑定在一起。因为无法令引用重新绑定到另外一个对象,因此引用必须初始化。
引用即别名:引用并非对象,相反的,他只是为一个已经存在的对象所起的另外一个名字。
定义了一个引用之后,对其进行的所有操作都是在与之绑定的对象上进行的。为引用赋值,实际上是把值赋给了与引用绑定的对象。获取引用的值,实际上是获取了与引用绑定的对象的值。
2、指针:
是指向另外一种类型的复合类型。与引用类似,指针也实现了对其他对象的间接访问。然而指针与引用相比又有很大的不同点。其一,指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它还可以先后指向几个不同的对象。其二,指针无需在定义时候就赋值,和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。
int * p;p是指向int类型对象的指针。
获取对象的地址:指针存放某个对象的地址,要想获取该地址,需要使用取地址符号(&)int val=24;int * p=&val;//p值存放变量val的内存地址,或者说p是指向变量val的指针。
因为在声明语句中指针类型实际上被用于指定他所指向对象的类型,所以二者必须匹配。
指针值:(即地址)因属于4种状态之一:
1、指向一个对象
2、指向紧邻对象所占空间的下一个位置。
3、空指针,没有指向任何对象。
4、无效指针
利用指针访问对象:如果指针指向了一个对象,则允许使用解引用符(*)来访问对象:int val=32;int * p=& val;cout<<*p;
解引用符只是应用于那些确实指向了某个对象的有效指针。
空指针:不知向任何对象,在试图使用一个指针之前代码首先检查他是否为空。
赋值与指针:指针和引用都能提供其他引用对象的简介访问,然而具体实现细节上二者有很大的不同,其中最重要的一点就是引用本身并非一个对象。一旦使用了引用,就无法令其在绑定到另外的对象,之后每次使用这个引用都是访问它最初绑定的那个对象。
指针和他存放的地址之间就没有这种限制。给指针赋值就是令他存放一个新的地址,从而指向一个对象:
int i=43;
int * p1=0;//p1被初始化没有指向对象
int * p2=& i;//p2被初始化,存有i的地址
int * p3;//这是个野的指针
p3=p2;//p3和p2指向同一个对象
p2=0;//p2不指向任何对象
注意:等号=永远改变的是等号左边的对象。
void *指针:
void* 是一种特殊的指针类型,可用于存放任意对象的地址。一个void*指针存放值一个地址,这一点和其他指针类似。不同的是,我们对该地址到底是个什么类型的的对象并不了解。
指针和引用的主要区别:
指针和引用在C++中很常用,但是对于它们之间的区别很多初学者都不是太熟悉,下面来谈谈他们2者之间的区别和用法。
1.指针和引用的定义和性质区别:
(1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用跟原来的变量实质上是同一个东西,只不过是原变量的一个别名而已。如:
int a=1;int *p=&a;
int a=1;int &b=a;
上面定义了一个整形变量和一个指针变量p,该指针变量指向a的存储单元,即p的值是a存储单元的地址。
而下面2句定义了一个整形变量a和这个整形a的引用b,事实上a和b是同一个东西,在内存占有同一个存储单元。
(2)可以有const指针,但是没有const引用;
(3)指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)
(4)指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;
(5)指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。
(6)"sizeof引用"得到的是所指向的变量(对象)的大小,而"sizeof指针"得到的是指针本身的大小;
(7)指针和引用的自增(++)运算意义不一样;
2.指针和引用作为函数参数进行传递时的区别。
(1)指针作为参数进行传递:
#include<iostream>using namespace std;void swap(int *a,int *b) { int temp=*a; *a=*b; *b=temp; }int main(void) { int a=1,b=2; swap(&a,&b); cout<<a<<" "<<b<<endl; system("pause"); return 0; }
结果为2 1;
用指针传递参数,可以实现对实参进行改变的目的,是因为传递过来的是实参的地址,因此使用*a实际上是取存储实参的内存单元里的数据,即是对实参进行改变,因此可以达到目的。
再看一个程序;
#include<iostream>using namespace std;void test(int *p) { int a=1; p=&a; cout<<p<<" "<<*p<<endl; }int main(void) { int *p=NULL; test(p); if(p==NULL) cout<<"指针p为NULL"<<endl; system("pause"); return 0; }
运行结果为:
0x22ff44 1
指针p为NULL
大家可能会感到奇怪,怎么回事,不是传递的是地址么,怎么p回事NULL?事实上,在main函数中声明了一个指针p,并赋值为NULL,当调用test函数时,事实上传递的也是地址,只不过传递的是指地址。也就是说将指针作为参数进行传递时,事实上也是值传递,只不过传递的是地址。当把指针作为参数进行传递时,也是将实参的一个拷贝传递给形参,即上面程序main函数中的p何test函数中使用的p不是同一个变量,存储2个变量p的单元也不相同(只是2个p指向同一个存储单元),那么在test函数中对p进行修改,并不会影响到main函数中的p的值。
如果要想达到也同时修改的目的的话,就得使用引用了。
2.将引用作为函数的参数进行传递。
在讲引用作为函数参数进行传递时,实质上传递的是实参本身,即传递进来的不是实参的一个拷贝,因此对形参的修改其实是对实参的修改,所以在用引用进行参数传递时,不仅节约时间,而且可以节约空间。
看下面这个程序:
#include<iostream>using namespace std;void test(int &a) { cout<<&a<<" "<<a<<endl; }int main(void) { int a=1; cout<<&a<<" "<<a<<endl; test(a); system("pause"); return 0; }
输出结果为: 0x22ff44 1
0x22ff44 1
再看下这个程序:
这足以说明用引用进行参数传递时,事实上传递的是实参本身,而不是拷贝。
所以在上述要达到同时修改指针的目的的话,就得使用引用了。
#include<iostream>using namespace std;void test(int *&p) { int a=1; p=&a; cout<<p<<" "<<*p<<endl; }int main(void) { int *p=NULL; test(p); if(p!=NULL) cout<<"指针p不为NULL"<<endl; system("pause"); return 0; }
输出结果为:0x22ff44 1
指针p不为NULL