C语言万字精讲指针

📅 2026/7/7 10:42:52
C语言万字精讲指针
前言很多初学者学C语言都会卡在指针分不清数组指针和指针数组、搞不懂 sizeof 和 strlen 、二维数组传参一头雾水、函数指针看不懂、笔试题一做全错。指针本质只有一句话指针 内存单元编号 地址。本文结合全套课件知识点由浅入深逐层拆解配套可运行代码高频笔试题看完彻底告别指针困惑。一、指针底层基础内存与地址1.1内存编址原理计算机内存被切分成一个个1字节内存单元每个单元分配唯一编号这个编号就是地址也就是指针。32位系统32根地址总线地址占4字节64位系统地址占8字节。所有指针变量大小只由系统位数决定和指向类型无关。1.2两大核心操作符1.取地址操作符a就可以取出地址拿的是字节较小的那个地址。int*paapa可以用来存放地址指针所以pa叫指针变量。这个int*pa叫做整型指针变量。*是在说明指针变量int是告诉我们pa指向的变量是int类型。pa类型是int*但是理解时int和*都有意义。2.取地址操作符间接访问操作符*pa*——解引用操作符通过pa里存的地址找到a1.3指针类型的意义1.指针的解引用一次访问几个字节比如int*访问4个字节、char*访问1个字节、double*访问8个字节、short*访问2个字节。2.由上两图可知p所存放的地址往后跳了四个字节。这是因为p的类型是int*p认为自己指向的是int类型数据pi1就应该跳过1个int类型的数据也就是4个字节。由此可知指针类型决定了向前或向后跳过的距离有多大。3.void*指针理解为无具体类型的指针不能直接进行解引用和或-整数的操作。一般就是使用在函数参数的部分用来接受不同类型数据的地址二、指针进阶const修饰指针、野指针与传址调用2.1const修饰指针1const修饰变量比如const int n 10 //常变量是变量但是具有常属性不变的属性。那么const修饰指针时也有异曲同工之妙。2const修饰指针1const放在*的左边 const int * p n---------------在这种情况下不让改*p但是可以通过修改pn这种方式修改n的值。这种写法限制的是指针变量指向的内容。2const放在*的右边 int * const p n----------------在这种情况下不让修改pn但是可以通过修改*p这种方式改变n的大小。这种写法限制的是p这个指针变量。3const放在*的左右两边p和*p指向内容都不能修改了。2.2野指针成因与规避1. 野指针它是指针但是指向的位置是不可知的。2.成因1指针未初始化2指针越界访问指针指向的范围超出arr数组的范围时p就是野指针3指针指向的空间释放。比如说当n是局部变量时如果在主函数中再用p来保存n的地址这时p就是野指针。3.规避1指针初始化如果明确知道指针指向哪里就直接赋值地址如果不知道指针应该指向哪里可以给指针赋值NULL。int *p NULL2小心指针越界3避免返回局部变量地址2.3传值调用和传址调用1.传值函数创建临时副本无法修改外部实参2.传址传递变量地址函数内可直接修改外部变量交换数字实例三、数组与指针核心规则3.1数组名两大例外1.sizeof数组名数组名代表整个数组计算数组总字节2.数组名取出整个数组的地址类型为数组指针3。其余场景数组名数组首元素地址。区分arr与arrint arr[10]{0}arr 1;//跳过1个int4字节arr 1;//跳过整个数组40字节3.2sizeof和strlen特性sizeofstrlen本质C语言操作符string.h函数计算内容占用内存总字节\0前有效字节个数参数类型、变量、数组、指针均可仅接收字符指针必须有\0终止风险无越界问题无\0会持续越界查找返回随机值3.3字符数组和字符串常量指针char arr[] abcdef;//栈上数组可修改元素char* p “abcdef”//指向常量字符串只读“p”修改会崩溃首字符a的地址放到了p里常量字符串会存入只读数据段多个同字面量指针指向同一块内存字符数组每次开辟独立栈空间。3.4指针数组和数组指针1.指针数组int*p[10]:数组每个元素是int*指针2.数组指针int*p[10]:指针专门存放数组指针。3.5二位数组与数组指针二维数组的本质存放一维数组的数组数组名arr是第一行一维数组的地址类型为int(*)[列数]。访问元素:*(*(pi)j) p[i][j]四、二级指针、指针运算与经典笔试题4.1二级指针char**或int**存储一级指针变量的地址两大用途1函数内修饰一级指针本身2接收指针数组数组名int a 10int* p aint**pp p**pp 100//等价a 100*pp NULL//等价p NULL4.2三种指针运算1.指针或-整数按指向类型步长偏移2.指针-指针仅同一块连续内存有效返回中间元素个数3.指针关系运算 比较地址高低仅数组内合法。4.3笔试例题解析X86 32位指针4字节例1例2五、函数指针、回调函数、qsort快速排序5.1函数指针基础函数名函数地址函数名等价函数名定义格式返回类型*指针名参数列表例如int Add(int x, int y) { return xy; }int (*pf)(int, int) Add;printf(%d, pf(2,3)); // 等价(*pf)(2,3)5.2回调函数定义将函数指针作为参数传给另一个函数由对方在内部调用被调用的函数即为回调函数。5.3qsort快速排序回调函数核心应用函数原型void qsortvoid*base//数组首地址size_t num,//base指向的数组的元素个数size_t size,//每个元素的大小单位是字节int(*compare)(const void*p1,const void* p2)//函数指针指向的函数可以比较数组中的两个元素//p1指向的元素比p2指向的元素小返回小于0的数字一样大返回0p1比p2大返回大于0的数字。例子测试qsort来排序整型数组六、指针避坑总结1. 数组传参退化为指针函数内部无法用 sizeof 求数组长度2. strlen 参数必须带 \0 字符数组无结束符会越界3. 常量字符串 char* p xxx 只读禁止解引用修改4. 区分 int (*p)[N] 数组指针和 int* p[N] 指针数组5. 函数返回禁止返回局部栈变量地址6. void* 不能直接解引用、不能±整数7. 数组名 是整个数组地址1跳过全部数组元素8. 二级指针只能接收一级指针的地址不能直接赋值普通变量地址。