浅解C语言指针
说到「指针」一定会联系到 C 语言。虽然 java/go/php/python 等 C 系语言都属于 C 的衍生品,但“指针”只是在 C 语言中大行其道。也正时由于指针,使C 语言成为开发大型系统(操作系统、游戏引擎等)的不二之选,可以说指针是 C 语言的灵魂。
同时,能不能灵活的使用指针,也是衡量 C 程序员的功能底的标准之一。
内存与指针
一个程序运行所需的所有数据都存储在内存中,CPU 通过访问内存获取「指令信息」与「数据信息」,进而进行逻辑操作...
而记录这些信息在内存中位置的变量即为「指针」。
内存地址与指针变量
变量:程序中把代表着一定信息的符号称为变量,如int a = 10
内存地圵:信息在内存中的位置,如 0x7ffd4506b0e4
变量与内存地址:程序运行时需要把 a=10 这个信息存储在内存中,存储的这个位置就是地址 &a
指针变量:首先它是一个普通的符号 int *p = &a,不过它对应的内存中存储的信息是一个地址 0x7ffd4506b0e4
指针变量与内存地址:存储指针变量的内存中的值是 0x7ffd4506b0e4,存储的位置是 &p
指针变量与指针类型
指针变量 p 是一个值
如 0x7ffd4506b0e4,代表其在内存中的某个位置,*p 即为访问这个位置
通过修改 p 的值,理论可以通过 *p访问内存的任意位置
指针类型告诉程序应该怎么理解这块内存
int *p=0x7ffd4506b0e4, 代表内存在 0x7ffd4506b0e4 处存储的值是一个 int
float *p=0x7ffd4506b0e4, 代表内存在 0x7ffd4506b0e4 处存储的值是一个 float
struct XXX *p=0x7ffd4506b0e4, 代表内存在 0x7ffd4506b0e4 处存储的值是一个 XXX 这个结构
对于 int *p 在访问 *p 时,程序在内存中取 sizeof int个字节
对于 struct XXX *p 程序在访问内存时读取 sizeof (sruct XXX) 个字节
int * 解析思路 * int 我是一个指针,我指针向一个 int 结构
struct X{ int a; int b;}X 中的偏移 offset &((struct X*)(p)->b) - p技巧: offset = &((struct X*)(0)->b) 把 0 当作某 X 数据的指针,则 offset 处存储的即为 bshort a = 0x1122;char c = *(char*)(&a)c == 0x22 // 小端存储c == 0x11 // 大端存储
函数指针
如上所属,程序运行中所需的信息(函数体、数据)需要放在内存中。而指针的存在即为了定位内存中的这些数据。
用于定位数据的指针即为变量指针;用于定位数据的指针即为函数指针
void (*f)(int) = 0x7ffd4506b0e4: 代表内存在 0x7ffd4506b0e4 处存储的是一个函数 (接受参数 int 返回类型 void)
voidoutput(inta){printf("%d\n",a);}void(*f)(int)=&output;// 习惯性写作: void (*f)(int) = output; f(10);// 即会输出 10
一切皆是指针
因为一切都在内存里,因为一切都是内存里的数据(0/1),因为 CPU 正常工作依靠在内存中读写数据。
所以 C 语言中的所有符号都是指针
普通变量与指针变量
inta=10;// 假设 &a 等于 0x7ffd4506b0e4a+=2
程序编译结果 (涉及编译链接原理)
声明 10 要放在 0x7ffd4506b0e4 内存处
a += 2 直接会编译成 *(0x7ffd4506b0e4) += 2
因为 int a,程序把 0x7ffd4506b0e4 的数据按 int 解析
inta=10;// 假设 &a 等于 0x7ffd4506b0e4int*p=&a;// 假设 &p 等于 0x7ffd4506a111(*p)+=2
程序编译结果
声明 10 要放在 0x7ffd4506b0e4 内存处
程序执行时
0x7ffd4506b0e4 被存储到 0x7ffd4506a111 位置
(*p) += 2 在 0x7ffd4506a111 读取到 0x7ffd4506b0e4
*(0x7ffd4506b0e4) += 2 因为 int *p,程序把 0x7ffd4506b0e4 的数据按 int
指针语法糖
指针的指针
inta=10;int*p1=&aint**p2=&p1// 即 p2 存的是一个指针的地址
int ** 的解析方式即 ** int: 我是一个指针,我指针一个指针结构,这个“被指向的指针结构”指向一个 int 结构
数组指针与指针数组
chara[10];char*p=a;// 这个指针指向数组char*p[10];// [10]*char 这是一个长为10的数组,里面存了一堆指针,指针指向 char 结构
指针常量与常量指针
charachar*constp=&a;// const * char p 中一个常量指针,指针 charcharconst*p=&a;// * const char p 是一个指针,指向 const char
因为指针过于灵活,需要限制指针功能
char * const p p 不能再赋其它值
char const *p *p 不能再赋其它值
函数指针与返回指针的函数
char*func()// 返回指针的函数void(*f)(int);// 函数指针
返回指针的函数指针
char*(*f)(int);
返回函数指针的函数
intf1(inti){returni*2;}int(*f1())(int){returnf2;}printf("%d",f1()(4));
返回函数指针的函数指针
typedefint(*t())(int);intf1(inti){returni*2;}int(*f2())(int){returnf1;}intmain(){t*func_t=f2;printf("%d",(*func_t)()(2));}