指针本质(pointer)
指针是一个整数,一种存储内存地址的数字。
类型只是人为规定,与指针本质无关。可以参考之前的变量类型。
32位编译模式下,一个指针占4byte(不是系统位数)
64位编译模式下,一个指针占8byte
具体可参考
一个小重点
对变量来说,类型的作用是,告诉机器需要多长的内存来存这个数据。另外,当想通过指针改变所指地址的值时,需要知道这个地址所存数据的长度,因此指针也会有对应的类型(指针所指的地址是所存数据的起始地址,如数组)。
指针的定义与使用:
// 一个整数变量var
int var = 8;
// ptr是指针,声明时加*告诉机器这是个指针,
// 对指针赋的值是想追踪的某个变量的地址,&代表取地址
int *ptr = &var;
// 通过指针访问所指变量,在该指针前加*
*ptr = 10;
// 多重指针道理相同,当前指针保存的是指针地址
int **ptrr = &ptr;
cout<<**ptrr<<endl; // 输出是var的内容
引用(reference)
引用是为变量起的别名。
int a = 5;
int &ref = a;
这个引用ref并不是一个真的变量,而是a的一个别名。这也就意味着引用在定义时必须赋值,后面也不能改变,但指针后续是可以改变的。例如:(下面代码接上文)
int b = 8;
ref = b;
这个操作相当于令a=b,而不是让ref引用b。
下面的代码更可以说明引用不是一个真的变量:
int main(){
int a = 5;
int &b = a;
cout<<&a<<endl;
cout<<&b<<endl;
}
输出语句中的&是取地址,此时输出是相同的,也就意味着b并不是一个变量,而是a的别名。
引用可以让代码更简单
Increment函数的功能是将变量加1。
void Increment(int value)
{
value++;
}
int main(){
int a = 5;
Increment(a);
cout<<a<<endl;
cin.get();
}
按上述写法的话,Increment并没有将a本身作为参数,而是新建了一个临时变量:int value=5。此时输出为5,即a本身的值并没有改变。
要想让Increment改变a的值,可以用指向该地址的指针做到:
// 这里参数是指针
void Increment(int *value)
{
// 对指针取地址以后再+1,不加括号则是对地址+1再取地址了
(*value)++;
}
int main(){
int a = 5;
// 传入地址
Increment(&a);
cout<<a<<endl;
cin.get();
}
这里相当于Increment创建临时指针:int *value = &a,取value所指地址的值+1。但是这样很麻烦。
使用引用:
void Increment(int &value)
{
value++;
}
int main(){
int a = 5;
Increment(a);
cout<<a<<endl;
cin.get();
}
这里相当于Increment创建临时的引用:int &value = a,因此后续修改value就相当于修改a。
引用的功能没有指针全面,但是可以简化代码(语法糖)
这里也可以看出函数的运行过程:【定义临时变量(上例中的value),并用所传参数为临时变量赋值(a或&a)】,运行函数体,return
其中括号【】中为一步,即上述的int value=5;int *value = &a;int &value = a
*和&的含义
*和&的使用容易混:
在定义时使用*或&,意味着定义变量为指针或引用。
int a = 0;
// ptr指向0地址,相当于ptr = nullptr
int *ptr = 0;
int &ref = a;
在其他使用时,意味着取内容或取地址
int *ptr = &a;
int &b = a;
再次强调:
指针的本质就是个整数,这个整数值是他所指的地址。
引用的本质是别名,并不是变量。