指针也是一种数据类型,具备指针类型的变量叫指针变量。指针变量的做用是存放单元地址
。c++
//语法:数据类型 * 变量名 例: int * ptr = 1;
指针为何要指明其类型编程
类型包括了指针所指向的元素所须要的内存空间大小数组
指针参与运算是跟指针对象类型是密切相关的。数据结构
指针值得是内存单元的地址。指针变量指的是存储地址的变量,也就是存储指针的变量。二者的区别须要注意。函数
*
/ &
C++提供两个与地址有关的运算符*和&。在不一样的运用场景中他们有着不一样的做用。下面咱们来讨论他们在各类不一样场景中的应用。测试
*
称为指针运算符,也称为解析(dereference):this
* 用来定义指针变量spa
加在指针变量以前表示解析当前指针变量,取其所指向的对象指针
cout << * ptr << endl; // 1
&
称为取地址运算符。code
& point能够取到变量point所指向的元素的地址。
&出如今变量声明中表示声明引用。
出如今赋值语句中,表示取右边对象的地址。
int * p = &i;
就像普通变量同样,指针在定义以后必须赋值才能引用。如定义的那样,指针变量存储的就是地址。因此指针变量赋值的语法以下数据类型 * 指针名 = 初始地址;
,但赋值的地址必须是已经定义过的常量(eg:数组名称实际上就是一个指针常量),对象或变量,结构体等,不然会引发空指针异常。
int a[10]; //定义int型数组,同时用a指针常量记录数组的首地址 int * ptr = a; //定义并初始化int型指针 int * const p2 = &a; //固然咱们也能够本身定义指针常量
指针是一种数据结构,和其余数据结构同样,指针也是数据+操做。可是指针参加的运算又与其余的操做不太同样。
指针能够参加整数的加减运算,可是又与普通的加减运算又一点区别,指针参加的加减运算与指针的类型密切相关。
ptr + nl; //表示当前ptr指针后方第nl个数据的地址。 ptr++;ptr--; *(ptr+nl); ptr[nl]; //表示ptr以后第nl个元素的内容。也能够写做ptr[nl],因此如今对数组的访问是否是点想法了呢?
PS:通常来说,指针的运算是和数组联合使用,由于只有数组会开辟一段连续的地址空间,同时若是使用这种方式必定要注意下标越界检查。
前面介绍了指针的算术运算,接下来介绍指针的关系运算。
指针能够和0进行比较,0用来表示空指针,也就是不指向任何一个有效地址。
PS:空指针也经常用NULL(NULL是一个经常使用的宏定义,其定义其实也是0
)来定义。在定义一个指针以后不知道指向什么地方的时候,必定要将转为空指针,避免错误调用形成一些不可碰见的错误。
指针数组:若是一个数组的每个元素都是指针变量,那么这个数组就是指针数组。指针数组的每一个元素都是统一类型的指针。
int * ptrArray[capacity]; //读者能够自行猜测根据前面讲的指针加法运算考虑下指针的二维数组。
想象一下一个在没有指针的状况下若是你要传递一大堆数据到一个函数中。这是个噩梦,就算你真的把全部参数都写了一遍,这个函数也不具备广泛性和可适用性。同时再想像一下当你须要返回的参数有一堆的时候,若是没有指针,根本无法实现对吧。
使用指针做为函数参数有几点好处:
实参和形参共享内存空间。也就是参数的双向传递。
减小数据传输时的开销。
经过指针也能够指向函数代码的首地址。
PS:若是参数对象并不须要作任何修改,咱们应该在参数列表中将它定义为常量指针。
虽然在传入参数的时候传入指针和对象的引用是一回事。可是应用会使程序的可读性更好些。
当一个函数的返回值是指针类型的时候这个函数就是一个指针性函数。而指针型函数的主要目的就是在函数结束的时候把大量的数据返回。
语法格式以下:
数据类型 * 函数名(参数列表){}
前面提到咱们在须要返回一堆数据的问题,当然咱们能够传入这堆数据的指针,实现前面所说的双向传递。可是这样可读性较差,同时会破坏本来传入数据的本来,若是你后面还要用原来的数据的话,那么这样干基本就GG了。
函数指针的正解是指向函数的指针。
在咱们日常调用函数的时候每一个函数都有一个函数名。是的你没猜错,指针又来了。调用函数的时候咱们一般的形式是函数名(参数列表)
其实质上就是函数代码的地址。那么函数指针就具备和函数名相同的做用。
函数范围值类型 (* 函数指针名)(参数列表)
那么很多读者会疑问void
返回类型的函数怎么办?在仔细思考一下,void类型的函数指针实际上是存在的。可是void类型的指针不管是使用仍是理解都有必定的难度。
void类型的指针没有类型,或则说不知道所指的对象长度。
PS:感兴趣的读者能够想象如何构建一个能够存储任何类型的数组。之因此是数组只是为了方便查找快。
任何类型的指针均可以赋值给它,而且不须要转换。但相应的问题是它只能得到对象的地址,而不能得到对象的大小。
因为不能明确长度,因此你能猜到咱们没法使用它参与指针运算。
没法复引用,也就是说没法解析。由于没有void类型的解析规则。
假如
int * p
,那么在你解析的时候,程序知道将该指针后的四位做为对象的内容。可是咱们前面说过void类型不知道所指向类型的长度。也就没有对应的解析规则,应用程序就没法解析了。
->
和.
的理解 咱们前面知道了指针能够指向一个对象,那么来想象一下若是我指向一个结构体(类通常成员私有,很差作例子)当我用指针指向他的时候我须要访问它的成员我须要这样写。
MyStruct * ptr = new MyStruct(); (* ptr).member; //巨麻烦有木有
请饶恕我懒癌晚期,可是每次能少些就少些,因此定义对于指针变量,须要访问其指向的指针对象时。咱们能够直接使用.
来访问。因而上面一段就变成了ptr->member
。嗯,顺眼多了。
不论哪一种语言,你们都没少写this
这颗指针吧,别否定,呵呵,我不信。
this
指针是一个隐含于每个类的非静态成员函数中的特殊指针。它用来指向正在被成员函数操做的对象。PS:this实际上类成员函数的一个隐含参数,在调用类成员函数时,目的对象的地址会自动做为该参数的值。这样被调用的函数就能访问当前目的对象的数据成员了。
*
SO:结合前面讲的->
和.
的区别你知道为何this以后你只能使用->
了吧。
对通常应用而言,把引用理解为指针,不会犯严重语义错误。引用是操做受限了的指针(仅允许取内容操做)。想象一下,指针能够对你的对象或者变量进行增删改查,他的权限对于有些应用来讲是否是太大了。
指针可以毫无约束地操做内存中的如何东西,尽管指针功能强大,可是很是危险。
就象一把刀,它能够用来砍树、裁纸、修指甲、理发等等,谁敢这样用?
若是的确只须要借用一下某个对象的“别名”,那么就用“引用”,而不要用“指针”,以避免发生意外。
好比说,某人须要一份证实,原本在文件上盖上公章的印子就好了,若是把取公章的钥匙交给他,那么他就得到了不应有的权利。
----「高质量c++编程」
指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
指针是一个实体,而引用仅是个别名;
引用使用时无需解引用(*),指针须要解引用;
引用只能在定义时被初始化一次(PS:必须初始化,且不为空,甚至指向空指针都不行。),一旦引用被初始化,就不能改变引用的关系(指针则能够随时改变所指的对象)。引用“从一而终” ❤️
引用没有 const,指针有 const,const 的指针不可变;
引用不能为空,指针能够为空;
“sizeof 引用”获得的是所指向的变量(对象)的大小,而“sizeof 指针”获得的是指针自己(所指向的变量或对象的地址)的大小;
指针和引用的自增(++)运算意义不同;
在c++中参数传递和返回值的传递有三种方式:
值传递
void function1(int x){ x = x + 10; } int n = 0; //实际上传递的是n的副本,并非n真实地址所指向的那个对象。 function1(n); cout << "n = " << n << endl;// n = 0
指针传递
//指针传递的是变量的地址,咱们直接修改地址,等同于修改了原变量 void function2(int *x) { (* x) = (* x) + 10; } int n = 0; function2(&n); cout << "n = " << n << endl; // n = 10
引用传递
//传递的引用,这里的X只是n的另一个名字,其指向的地址仍是x的地址。 void funcion3(int &x) { x = x + 10; } int n = 0; function2(n); cout << "n = " << n << endl; // n = 10
由于引用确定会指向一个对象,引用应被初始化。
PS: 不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针的要高。由于在使用引用以前不须要测试它的合法性。
指针与引用的另外一个重要的不一样是指针能够被从新赋值以指向另外一个不一样的对象。可是引用则老是指向在初始化时被指定的对象,之后不能改变。
string s1("Nancy"); string s2("Clancy"); string & rs = s1; // rs 引用 s1 string * ps = &s2; // ps 指向 s2 rs = s2; //引用不用解析能够直接赋值,如今rs仍旧引用s1,可是s1的 rs 指向的是值如今是 "Clancy" ps = &s1; // ps 如今指向 s1; cout <<" rs 指向的内容是" << rs << endl; cout <<" ps 指向的内容是" << *ps << endl;