指针的定义
指针的含义包含三个方面:变量、地址、内存宽度:
变量:指针是一个变量,x86占4个字节,x64占8个字节。
地址:指针的值是一个内存地址,指向内存的某一个地方。
内存宽度:指针明确了指向内存的宽度,通过指针的类型确定。
在定义指针的时候,*和类型结合,表示指针的类型; 在使用指针的时候,*和指针结合,表示解引用。
指针的初始化
可以让指针指向某个变量的地址,也可以让指针指向一个分配的内存或者字符串常量,还可以指向NULL。
取地址运算符&取变量的地址,reference,引用。
&和*互为逆运算。
解引用运算符*取地址对应内存中的内容,dereference,解引用。
解引用运算符后面必须是指针,不能为无效的内存,也不能为NULL,否则程序运行会崩溃。
定义一个指针p,*p表示通过指针指向的内存地址,找到对应的内存和里面存放的数据,进行读取或者修改操作。
指针的数据类型
定义一个指针,指针类型的变量长度为4或者8,即sizeof(p)= 4or8,指针所指类型的长度为sizeof(*p)。
void*类型的指针变量,没有指定内存的宽度,其他类型指针隐式转换成该类型,不能用*p解引用取值,需要先转换成特定类型再取值。对于指针变量void* p:
p可以接受任何类型的指针。
p赋值给其他类型指针时需要强转。
p不能直接进行解引用运算,必须先转换。
p不能直接进行加减算术运算,必须先转换。
char*类型的指针变量,既可以指向字符,也可以指向字符串,即字符串首个字符的地址。字符指针初始化时,字符使用单引号,字符串使用双引号。
指针的运算
指针支持加减运算,不支持其他算术运算。对于指针p,指针的加法运算p+n,p向后移动的距离不是n个字节,而是n个指针所指类型的单位长度,即nsizeof(p),减法运算与此类似。
数组和指针
数组名是一个常量指针,指向数组的首地址,指针和数组名可以互相通用。
常量指针与指针常量
指针数组与数组指针
函数指针与指针函数
函数指针函数名,就是函数的地址。
函数的签名,包含函数的返回值类型,参数类型,参数个数。
如果一个指针变量,存放的是函数的地址,那么就把这个指针叫做函数指针,函数指针的类型由对应的函数签名来决定。
指针函数返回值是指针的函数。
指针函数不能返回局部变量的地址,指针或者引用,因为局部变量的地址会随着函数调用结束被自动释放,指针会成为一个野指针,可以返回堆上的内存地址。
定义函数指针的两种方法直接用函数的签名定义函数指针。
用typedef关键字定义函数指针的类型,再用指针类型定义函数指针。
vs2019中,为函数指针赋值,函数名func等同于&func。
二级指针
如果指针做实参,那么传实参的指针就必须使用二级指针,要在函数中改变指针的值,就必须传指针的指针。
指针的复杂声明
指针在声明的时候必须初始化,如果没有初始化,任何指针变量在被创建的时候,不会自动成为NULL指针,会随机的指向任何一个地址,它的缺省值是随机的,即野指针,访问野指针会造成不可预知的后果。
为什么要使用指针通过内存地址直接操作内存,性能高。
函数传参时,传指针比传值可以减少拷贝,效率高。
复制指针之后,解引用取出数据,无论在时间还是空间上,都比直接复制及访问数据高效。
指针可能跑飞,破坏其他部分的程序数据,造成内存泄露。
传引用比传指针安全。
github:https://github.com/0I00II000I00I0I0
bilibili:https://space.bilibili.com/284022506