一、指针的定义
1.本质
指针,就是存储地址值的变量。(我们设计一个地址类型的变量,用来存放其他变量的内存地址)
2.指针的大小
1.指针占多少字节取决于CPU架构:x86架构(32位):指针大小为4字节
x64架构(64位):指针大小为8字节
2.在内存分配上,Windows通常是用户2G+内核2G,Linux是用户3G+内核1G
3.指针的三种初始形态
- 野指针(悬挂指针):int* p;//定义但未初始化
- 空指针:int* p=NULL;//安全的初始化方式
无类型指针:void* p=&val;//可以接受任意类型变量的地址。注意:void*不能进行解引用,也不能进行算术运算。
二、const的用法
- 常量:不能被修改,也不能取地址
- 常变量:具有常性,值不能修改,但可以取地址
const修饰变量时,会使其具有“常性”
const double PI=3.14; const double* p=Π//const限定*p具有常性,即p指向的值不允许通过p修改 double * const q=&val;//p本身具有常性,即不允许修改p的指向 const double* const s=#//指针自身和指针指向的值都具有常性,不允许被修改当const修饰指针是:看类型,自右向左看,权限只能缩小不能放大
const int val=0; int* p=&val;//error!左边类型是int*,右边是const int* int val=0; const int * p=&val;//✅️三、指针运算
1.指针的类型决定了
- 解引用--解析的内存大小
eg:int* p= ;//*p解析的内存大小为int大小
int** q= ;//*q解析的内存大小为int*大小
- 指针+1能力(步长)
int arr[] = {1, 2, 3, 4, 5}; int* p = arr; *(p+1); // 访问第2个元素 // 本质:数组下标 arr[1] 完全等价于 *(arr + 1)
2.指针的加减法则
- 可以相减:同一内存空间的两个指针可以相减,结果是这两个指针之间相隔的元素个数
- 不可以相加
3.mem系列函数<stdlib.h>
- memset:逐字节进行,初始化内存(如memset(arr,0,sizeof(arr));)
- memcpy:内存拷贝,但不处理内存重叠区域
- memmove:内存拷贝,能够安全处理内存重叠的情况
四、指针数组和数组指针
1.指针数组
是一个数组,里面的每个元素是指针
int a,b,c; int* crr[]={&a,&b,&c}; const char* strs[3] = {"hello", "world", "sta"};// strs 是一个数组,包含 3 个 const char* 类型的指针2.数组指针
是一个指针,指向一个完整的数组
int arr[3]; int (*p)[3] = &arr; // 注意:不能写 int *p[3](那是指针数组) // p 的类型是 int(*)[3],它指向一个占 12 字节(3个int)的数组五、指针与函数
1.静态局部变量
在函数中使用static修饰局部变量,可以延长局部变量的生命周期,使函数返回后变量依然存在,保持上一次调用的值。
2.传址调用(指针做函数参数)
作用:1.在函数内部修改外部的实参
void Swap(int* pa, int* pb) //通过传址地址和解引用,真正交换了外部变量的值2.节省内存空间
3.输出型函数
有时候函数不仅需要返回执行状态(成功/失败),还需要返回“计算结果”。此时可以用返回值传状态,用指针参数带出结果
// 除法函数设计 bool div(int a, int b, int* pval) { if (b == 0) return false; // 状态:除数为0失败 *pval = a / b; // 结果通过指针写回 return true; // 状态:成功 } // 调用:int res; if(div(10, 2, &res)) { ... }