指针和引用
指针
const和一级指针
判断const 修饰的常量
const修饰的量常出现的错误是:
1.常量不能再作为左值《=(不然会直接修改常量的值)
如
const int a=10;
a=20;//尝试直接修改常量,错误
2.不能再把常量的地址泄露给一个普通的指针或者普通的引用变量(不然会间接的修改常量的值)
const int a=10;
int *p=&a;
//这样可以间接通过指针解引用方法修改内存a的值。
*p=20;
//正确的定义方式为
const int *p=&a;
C++的语言规范:const修改的是离它最近的类型(去掉类型(如int和int *,并且满足一个最少原则,如果是int *和int中选择,那么一定是int),去掉类型后其修饰的表达式就是不能改变的,即const)
指针指向地址的内容不能被修改
int a=10;
int b=100;
const int *p=&a;
int const *p=&a; //这个与上面那句是等效的,int 在const 左右均不影响
//这里去掉最近的类型,即 int ,const修饰的是*p,表示*p不能被修改。
*p=20; //错误
p=&b; //正确
//指针p可以指向任意不同的int类型的内存,但不能通过指针间接修改指向的内存的值
指针指向地址不能被修改
int a=10;
int b=100;
int * const p=&a; //const 最近且满足最少原则的类型应该是int *,则其修饰的表达是为 p,表示p不能被修改
//指针p是常量,不能再指向其他内存,但是可以通过指针解引用修改指向内存的值
p=&b; //错误
*p=20; //正确
注意
:const 如果右边没有指针*的话,const是不参与类型的。
int * q1=nullptr;
int *const q2=nullptr;
int const *q3=nullptr;
//这里q1和q2的类型都是 int *; q3的类型是int const *;
const和二级指针
int a=10;
int *p=&a;
//三种情况
//情况1
const int **q=p; //修饰的是 const **q,即不能通过q二级指针解引用修改q指向的一级指针指向的变量的值,**q不能被赋值
//情况2
int *const *q=p; //修饰的是 const *q,*q指向的一级地址的值不能被改变,*q不能被赋值
//情况3
int ** const q=p; //修饰的是const q,即q本身不能改变,q不能被赋值
总结 const 和 指针的类型转换公式
int * <<<=== const int * ;//是错误的!!!
const int * <<<=== int *; //是正确的!!!
int ** <<<=== const int **; //是错误的!!!
const int **<<<=== int **; //是错误的!!!
//在二级指针甚至多级指针中,两边都要有const 才算正确;
int ** <<<===int * const *;//是错误的!!!
//前面说到,const只负责其右边的类型构造,上面可以简化为
int * <<<===int const *; //判断错误
int *const *<<<=== int **; //是正确的!!!
//简化为 int const *<<<=== int *;
错误样例
int a=10;
const int *p=&a;
int *q=p;//这里 int *<<<===const int *,不匹配
int a=10;
int *p=&a;
const int **q=&p; //const int ** <<<=== int **,不匹配,&p取地址加一个*
int a=10;
int *const p=&a; //p为int *,const 只在其右边有指针时起作用;
int **q=&p;//因为这有一个取地址操作,则 int ** <<<===int *const *,不匹配
int a=10;
const int *p=&a;
int *const*q =&p; //int *const *<<<===const int **,左边是const 与一级指针结合,右边是const 与二级指针结合,不匹配(我是怎么理解的,不知道有没有更好的解释)
引用
定义
引用是一种更安全的指针。
int a=10;
int *p=&a;
int &p=a;
//如果不会定义引用,可以先写出指针形式,然后用等号右边的&符号覆盖等号左边的*,代码如上
//定义一个引用变量,来引用array数组
int array[5]={};
int *p=array; //4字节,指向array第一个数组内存
int (*q)[5]=&array;//5字节,指向array数组的指针,对应的引用应该这样写
int (&q) [5]=array;
1.引用时必须初始化的,指针可以不用初始化
2.引用只有一级引用,没有多级引用;指针可以有一级指针,也可以有多级指针。
3.定义一个引用变量和定义一个指针变量,其汇编指令是一模一样的;通过引用变量修改所引用内存的值,和通过指针解引用修改指针指向的内存的值,其底层汇编指令也是一模一样的。
左值引用和右值引用
左值引用
左值引用指的是引用的是有内存,有名字,其值可以修改的
//语法 T &
int a=10;
int &b=a;
//特殊的左值引用
const int &b=20;
右值引用
右值引用是是没有内存,没有名字的,如立即数20.
//语法 T &&
//c++11提供了右值引用
int &&c =20;
总结
const int &b=20;
int &&c =20;
//这两个代码底层原理都是一样的
//1.产生临时变量存储该常数
//2.然后直接引用临时量
int temp=20;
int &b=temp;
指针、引用和const的结合
//在内存的ox0018ff44处写一个4字节的10
int * const &p=(int *) 0x0018ff44 //特殊的左值引用以实现常量引用
*p=10
错误样例
int a=10;
int *p=&a;
const int *&q=p; //转换成const int **q=&p,则const int ** <<<===int **,不匹配
int a=10;
int *const p=&a;
int *&q=p; //转换成int **q=&p; 即 int **<<<===int *const *,不匹配
int a=10;
const int *p=&a;
int *&q=p; //转换成int **q=&p; 即int **<<<===const int **,错误
int a=10;
int *p=&a;
const int *&q=p; //转换成const int **q=&p; 即cosnt int **<<<===int **,错误
其他
注意
[]和()的优先级高于*。
数组指针和指针数组
数组指针
//数组类型的指针
//指针有各种类型 ,int *,float *
//将数组当作一种数据类型,定义一个指向数组的指针
int a=10;
int *pa=&pa;
int arr={1,2,3};
int (*pa) []=&arr;
//表明这是一个指针,并且指向一个数组,这个数组中的类型是int 类型
指针数组
int a=10,b=20,c=30;
int *arr[]={&a,&b,&c};
//arr先与[]结合,表示这是一个数组,并且这个数组的类型是int *
函数指针和指针函数
函数指针
//是一个指针,指向一个函数,函数返回类型是int 型
int (*fun) (int x);
指针函数
int *fun (int x)
//fun先与()结合,表示这是一个函数,返回类型为int *;