引用:给对象起了一个另外的名字,引用必须初始化
引用不是对象,它只是给已经存在的对象起了一个别名,所以对引用的所有操作,都是在与之绑定的对象上进行的
因为引用不是对象,所以不能定义引用的引用
引用类型要跟与之绑定的对象类型严格匹配,且只能帮在对象上,不能与字面值或表达式绑在一起
#include <iostream> int main() { int i =0; int &refi = i; // 引用不是对象,它是为已经存在的对象起了另一个名字 // int &refi2; // 编译报错,引用必须初始化 std::cout << refi << std::endl; // 0 refi = 2; std::cout << refi << std::endl; // 2 i = 3; std::cout << refi << std::endl; // 3 refi = 4; i = refi; std::cout << refi << std::endl; // 4 int &refi3 = refi; // 引用不是对象,所以不能定义引用的引用,这个引用也是绑在i上面的 refi3 = 5; std::cout << refi << std::endl; // 5 double d = 3.14; // int &refd = d; // 编译报错,绑定的对象类型与引用的类型不一致 // int &refi4 = 12; // 编译报错,不能绑定到字面值上 // int &refi5 = refi + i; // 编译报错,不能绑定到表达式上 return 0; }
指针:与引用类似,也实现了对其他对象的间接访问,存放的是某个对象的地址
指针与引用的不同:
1 指针本身是一个对象,允许对指针赋值或拷贝,在指针的生命周期里,它可以指向不同的对象
2 指针无需在定义时赋初值,如果没有初始化,将是一个不确定的值
指针的类型要与所指向的对象类型一致
利用指针访问对象,使用解引用符*
空指针:不指向任何对象 nullptr
void* 指针是特殊的指针类型,可用于存放任何对象的地址。但是对于该地址中存放的是什么类型的对象,并不知道。所以不能直接操作void*指针所指的对象
指针的指针:通过*的个数可以区分指针的级别,**表示指针的指针,***表示指针的指针的指针,以此类推
指向指针的引用:因为指针是对象,所以可以定义引用绑定到指针上
#include <iostream> int main() { int i =0; int *pi = &i; // &取地址符 std::cout << i << std::endl; // i的值 std::cout << pi << std::endl; // i的地址 std::cout << *pi << std::endl; // 访问指针所指向的对象,*解引用符 *pi = 7; // 修改所指向对象的值 std::cout << i << std::endl; std::cout << *pi << std::endl; double d = 3.14; double *pd1 = &d; // int *pd2 = &d; // 编译错误,指针类型与指向的对象类型不一致 int *pn1 = 0; // 空指针 int *pn2 = nullptr; // 空指针,推荐用法 int *pn3 = NULL; // 空指针,不推荐用法 i = 0; // int *pn4 = i; // 编译错误,把int变量赋给指针是错误的,即使这个变量的值是0 void *pd3 = &d; // *pd3 = 3.15; // 编译错误,void* 无法确认类型 int val = 17; int *pval = &val; int **ppval = &pval; // 指针的指针 std::cout << **ppval << std::endl; **ppval = 18; std::cout << **ppval << std::endl; int *&refpi = pi; // refpi是对指针pi的引用 refpi = &val; *refpi = 19; std::cout << val << std::endl; std::cout << *refpi << std::endl; return 0; }
变量的声明:
int* p1, p2; // *修饰的是p1,并不作用于p2, 所以这句话,声明了一个指向int的指针(p1),声明了一个int型(p2)