发表在 程序里的星辰与大海 09-05 07:51:46
自己看书时的一些理解,可能有错误的地方。随着指针的使用增多,会不断修改这篇文章的内容,过去错误的会用划线划去后保留。
1.符号是有多重含义的,这一点书里提到过,但很容易在读代码时被忽略
#include
//指针里符号的多重含义
int main()
{
int i = 0;
/*
1.这里的*不是解引用符而是类型修饰符,因为这是一条声明语句,声明语句=基本类型+声明符列表,声明符列表指类型修饰符+变量名。
2.类型修饰符的作用是指定了变量名是与基本类型相关的某种类型,所以我觉得这里更适合写int *p=&i,而不是int* p=&i,后者容易让人理解为int*是一种类型,当然这也没错。
3.这句声明语句,相当于:
int *p;
p=&i;
所以,绝对绝对不能把声明语句和表达式中的符号一视同仁。
*/
int *p = &i;
*(int*)p = 25;//因为类型不同,不能有*p=i这种操作,实在想赋值给指针,只能用强制类型转换
return 0;
}
2.对引用、指针、常量引用、指向常量的指针、常量指针的理解
#include
//对引用、指针、常量引用、指向常量的指针、常量指针的理解
int main()
{
//引用
int a = 1;
int &r_a = a;//只要是引用都必须初始化
r_a = 5;//引用不是一个对象,但可以通过改变引用来间接改变引用对象的值
std::cout << "引用 " << a << std::endl;
//指针
int b = 1;
/*
*同一符号在不同语句中有不同的意义。
*
*声明语句中,*是类型修饰符,表达式中,*是解引用符。
*
*声明语句=基本类型+声明符列表=int *p,其表示定义一个名为p、指向int类型的指针。
*
*int *p=&b;实际上等价于:
*int *p = nullptr;
*p=&b;
*如果想要给p赋int值,就要用上强制类型转换:
* *(int*)p=b;
*/
int *pb = &b;
int **pib = &pb;
int ***piib = &pib;//有3个*,表示pii是指向指针的指针的指针,最终指向的地址是&b
std::cout << "多重指针的指针 " << ***piib << std::endl;
//常量引用
int c = 9;
/*
*const是一个限定符,其限定了不能对某个对象进行任何改变。不管是引用还是指针,只要对象是常量,声明中必须有const
*
*从右往左读,“&”表示r_c是一个引用,“int”说明了这是一个对int类型的引用,
*“const”则说明这个引用是一个常量,即不能改变(这里的不能改变指的是引用绑定的对象不能变,不是值不能变)。
*
*c不能通过改变它的引用r_c而改变,但可以通过别的方式改变。
*
*r_c可以通过改变c来改变。
*
*常量引用有什么用呢?当我们需要对一个函数传入某个变量作为参数时,如果直接传要进行拷贝等工作浪费空间和时间,
*此时如果传入那个变量的引用就可以省去那些操作(引用并没有申请存储空间,引用本身不是一个对象),而我们又怕
*使用引用的时候不小心改变了那个变量,所以我们用了常量引用。
*
*如果这里的c是一个常量,则c、r_c都不能改;
*/
const int &r_c = c;
c = 10;
std::cout << "常量引用 " << c << " " << r_c << std::endl;
double d = 3.14;
/*
*引用的类型必须与其引用对象的类型一致,但有两个例外,其中之一就是在常量引用的初始化时,可以类型不一致,
*实际上它的执行是通过一个临时量来使其合法的:
*double d = 3.14;
*const int tem = d;
*const int &r_d = tem;
*在这里,无法通过改变d值来改变r_d(改变tem才行,但是tem是编译器为了类型转换而临时出现的,并不是一个真的对象)。
*需要说明的是,这种转换必须是可以互相转换的类型(double和int是可以互相转换的)
*
*不能用一个非常量引用来引用一个常量,即下面的语句是非法的:
*const int d = 3;
*int &r_d = d;
*/
const int &r_d = d;
d = 8.5;
std::cout << "常量引用类型不一致 " << d << " " << r_d << std::endl;
//指向常量的指针
const int e = 9;
/*
*从右往左看,“*pe”表示一个名为pe的指针,“int”表示这个指针指向int类型,“const”表示这个指针指向的是一个常量。
*
*指向常量的指针,只是说明不能通过改变指针来改变指向的对象,并没有说指针本身的值不能改变。
*
*指针的类型必须与其所指对象的类型一样,但是有两个例外,其中一个就是指向常量的指针,指向的对象不一定非得是常量。
*
*e是常量,则pr声明处的const不可省略,因为必须强调指向的是一个常量才能存e这个常量的地址;如果e不是常量,pe声明处的const意在
*指出不能通过pe指针来改变指针指向的对象,不管这个对象是不是常量——如果不是常量,可以通过除指针外的方式改变对象。
*书上一句话可以很好的概括这一点:所谓指向常量的指针或引用,不过是指针或引用“自以为是”罢了,它们觉得自己指向了常量,所以自觉的不去改变所指对象的值。
*
*指针和引用不一样,有关指针的初始化并没有类似引用中的tem这个中间值的执行步骤——即如果基本类型不一样是不能初始化的,只是说常量和非常量都可以初始化。
*也就是说,不要过度的类比指针和引用的操作,两者相同点没有那么多,比如这里的pe即使是自己和指向的对象都加了const,pe还是可以改变。
*/
const int *pe = &e;
const int f = 10;
pe = &f;
std::cout << "指向常量的指针 " << *pe << std::endl;
//常量指针
int g = 10;
/*
*从右往左看,“const”表示pg是一个常量,“*”表示pg是一个常量指针,“int”表示pg指向一个int对象
*
*常量指针必须初始化。
*
*常量指针不能改变(指向的地址不变),只能改变解引用后的值,即只能改变g值。
*/
int *const pg = &g;
g = 9;
std::cout << "常量指针指向非常量 " << *pg << std::endl;
/*
*一样的同上从右往左看,我们发现在指针的声明中,限定符const在声明列表里则是限定列表里指针,在基本类型处则是限定指针指向的对象,
*这里的ph表示一个常量指针指向一个int的常量h。由于都是常量,所以都不能改变。
*/
const int h = 4;
const int *const ph = &h;
std::cout << "常量指针指向常量 " <<*ph << std::endl;
return 0;
}
3.类型不同,读取的方式也是不一样的,之所以要求类型一致就是这个原因,同一串二进制,用int去读和用double去读读出来的结果是不一样的。引用实际上是一个存储地址存了两个名字,一个是引用名,一个是对象名。
这里不太懂