**
指针的定义形式:
**
指针本身也有对应的指针类型
int** iip; // 即(int*)* iip;
iip称为二级整型指针变量。
一个*只能修饰一个指针:
int* ip, iq; //其中ip为指针变量,iq为整型变量
int* ip,*iq; //定义两个指针变量
指针变量的定义,由数据类型后跟型号,再跟指针变量名组成。指针变量在不致引起混淆的情况下也称为指针。
指针可以复制们也可以在定义指针时初始化,赋值或初始化的值是同类型实体的地址:
int* ip;
int iCount =18;
int* iPtr =&iCount; //初始化
ip = &iCount; //赋值
& 表示实体的地址,由于字面值不认为是具有空间地址的实体,所以不能进行 & 操作
ip = &23; //错
指针指向的实体,可以通过指针的间访操作(即在指针变量前加*号的操作来读写该空间的内容)。例如:
int iCount =18;
int*ip =&iCount;
*ip=12;
cout<<*ip<<" "<<iCount<<endl;
//输出为 12 12 ,因此间访操作对所指向的实体可以读也可以写,写就意味着实体的改变
由于指针变量本身也为具有空间的实体,因此也具有空间地址,也可以被别的指针所操纵。例如,下面通过二级指针的两次间访,最终操纵整型实体。
int iCount =18;
int* ip =&iCount;
int** iip =&ip;
cout<<**iip<<endl;
*在不同的地方有不同的含义
int a =8;
int c= 12*a; //乘法操作符
int* ip =&c; //指针定义
cout<< *ip<<endl; //指针间访,间访操作只能用在指针上,否则变异报错
指针的0值不是表示指向地址0的空间,而是表示空指针,即不知想任何空间。儿指针只有指向具体的实体,才能是间访操作具有意义。
指针的类型
给指针赋值,不但必须是一个地址,而且应该是一个与指针类型相符的变量或常量的地址。图。“int* ip ;” 则ip为整型指针;“float* fp;”则fp为浮点型指针。
//空间实体的理解
#include<iostream>
using namespace std;
int main()
{
float f= 34.5;
int* ip= reinterpret_cast<int*>(&f);
cout<< "float address:"<<&f<<"=>"<<f<<endl;
cout<< "int address:"<<ip<<"=>"<<*ip<<endl;
*ip =100;
cout<<"int:"<<*ip<<endl;
cout<<"float:"<<f<<endl;
}
指针运算
指针值标识一个内存地址,因此它内部表示为整数,这在显示的时候可以看到。指针变量所占空间的大小总是等同于整形变量的大小。
指针不能富裕一个整型数。要想或得整型数标识的绝对地址,应将整型数重解释转换为对应的指针类型,例如:
int* ip =1234567; //error:不能进行int到int*的直接转换
int* sp = reinterpret_cast<>(1234567); //OK
指针的加减整型数大多用在数组这种连续的有事同类型元素的序列空间中。可以把数组起始地址赋给一指针,通过移动指针(加减指针)来对数组元素进行操作。数组名本身就是表示元素类型的地址,所以可以直接将数组名赋给指针。例如:
#include<iostream>
using namespace std;
int main()
{
int iArray[6];
for(int i=0; i<6; ++i)
iArray[i] =i*2;
for(int* iP=iArray; iP<iArray+6; iP+=1)
cout<<iP<<": "<<*iP<<endl;
}
指针限定
一个指针可以操作两个实体,一个是指针值(即地址),一个是间访值(即指向的实体)。于是指针的常量性也分为两种:指针常量(constant pointer)和常量指针(pointer to constant)。
指针常量是相对于指针变量而言的,也就是指针值不能修改的指针。
常量指针时指向常量的指针的简称。定义指针常量还是常量指针就看const修饰,若const修饰指针本身,则为指针常量,若修饰指针类型(指向的实体类型),则为常量指针。例如:
const int a =78;
int b =10;
int c =18;
const int* ip =&a; //const修饰指向的实体类型——常量指针
int* const cp =&b; //const修饰指针*cp——指针常量
int const* dp =&b; //等价于上一句——指针常量
const int* const icp =&c;//常量指针常量
*ip =87; //error:常量指针不能修改指向的常量,*ip只能做右值
ip=&c; //ok: 常量指针可以修改指针值
*cp =81; //ok:指针常量可以修改指向的实体
cp=&b; //error:指针常量不能修改指针值,即便用同一个地址
*icp=33; //error:常量指针常量不能修改指向的常量
icp =&b; //error:常量指针常量不能修改指针值
int d = *icp; //ok
const修饰只是限定指针的操作,但不能限定空间上的实体的可改变性。因为一个实体可能被不止一个变量所关联,所以实体被其他关联变量的改变是可能的。例如:
#include<iostream>
using namespace std;
int main()
{
int a =78,c=18;
const int* ip =&a;
const int* const icp =&c;
a=60;
c=28;
cout<<"ip==>"<<a<<endl;
cout<<"icp=>"<<c<<endl;
}
引用
从逻辑上理解,引用是个别名。当建立引用时,用一个有具体类型的实体去初始化别名,之后,别名便于关联其实体的变量(或对象)享受访问的同等待遇。
引用的定义形式如下:
引用定义时必须初始化,这是它与指针根本不同的地方。给引用初始化的总是一个内存实体。初始化的内存实体不是通过一个地址表示,而是通过一个代表该实体的名称表示的,它可以使变量也可以是常量。
使用引用,就等于一个实体又多了一个关联的名字,实体的值因而便任由关联的名称操作所宰割。因此,修改引用值,就是修改实体值,就是修改对用的变量值,而引用的地址操作也就是所代表的实体地址操作,是不会有任何变动的:
//引用及其地址
#include<iostream>
using namespace std;
int main()
{
int int1 =5;
int& rInt = int1;
cout<<"&int1:"<<&int1<<" int1:"<<int1<<endl;
cout<<"&rInt:"<<&rInt<<" rInt:"<<rInt<<endl;
int int2 =8;
rInt =int2;
cout<<"&rInt:"<<&rInt<<" rInt:"<<rInt<<endl;
}