指针与数组深度攻略:数组名、传参、冒泡、二级指针

张开发
2026/4/15 21:41:37 15 分钟阅读

分享文章

指针与数组深度攻略:数组名、传参、冒泡、二级指针
专栏C语言C语言指针3一.数组名的理解1.1 普通情况1.2 两个例外1.3 arr 与 arr 的核心区别二.使用指针访问数组三.一维数组传参的本质3.1函数内无法计算数组长度四.冒泡排序指针 数组4.1基础版函数部分4.2进化版函数部分五.二级指针六.指针数组七.指针数组模拟二维数组总结易错点本文是 C 语言指针系列第三篇我们将揭开数组名的真实面纱用指针遍历数组的每一寸空间深入理解一维数组传参、冒泡排序的实现逻辑并进一步探索二级指针这一 “指针的指针”学习指针数组如何搭建起模拟二维数组的桥梁。前言指针是C语言的核心特性也是学习路上的重点与难点。数组与指针的关联、二级指针、指针数组更是从入门走向进阶的必经之路。许多初学者因混淆数组名本质、不理解数组传参机制、无法区分二级指针与指针数组导致代码逻辑混乱、错误频发。我会以清晰的逻辑、通俗的讲解与代码案例系统梳理上述知识点从原理到实践层层拆解帮助大家真正理解并掌握为后续深入学习打下坚实基础。一.数组名的理解在学习数组和指针时数组名绝对是第一个要搞明白的关键点。先总结一下数组名就是数组首元素的地址但记住 ----- 它有两个非常重要的例外这是学习必坑点1.1 普通情况在前面数组提及过数组名 首元素地址#includestdio.hintmain(){intarr[10]{1,2,3,4,5,6,7,8,9,10};printf(arr[0] %p\n,arr[0]);printf(arr %p\n,arr);return0;}运行结果两个地址完全相同证明数组名就是首元素地址。强调一下绝大多数场景下数组名都代表首元素地址。1.2 两个例外sizeof(数组名)数组名表示整个数组计算整个数组的字节大小。 数组名数组名表示整个数组取出的是整个数组的地址。arr的类型是int*指向 int 的指针arr的类型是int(*)[10]数组指针指向整个数组两者地址值相同但意义完全不同1.3 arr 与 arr 的核心区别arr/arr[0]首元素地址1 跳过1 个元素4 字节。arr整个数组的地址1 跳过整个数组40 字节。#includestdio.hintmain(){intarr[10]{1,2,3,4,5,6,7,8,9,10};printf(arr[0] %p\n,arr[0]);printf(arr[0]1 %p\n,arr[0]1);printf(arr %p\n,arr);printf(arr1 %p\n,arr1);printf(arr %p\n,arr);printf(arr1 %p\n,arr1);return0;}运行结果二.使用指针访问数组理解数组名后用指针访问数组就更加轻松了。先总结一下数组下标访问本质就是指针解引用。如下所示#includestdio.hintmain(){intarr[10]{0};inti0;intszsizeof(arr)/sizeof(arr[0]);int*parr;for(i0;isz;i){scanf(%d,pi);}for(i0;isz;i){printf(%d ,p[i]);}return0;}数组名可直接赋值给指针arr[i]等价于*(arri)p[i]等价于*(pi)。数组下标访问本质arr[i]--*(arri)--*(iarr)–i[arr]所以arr[i]i[arr]语法合法因为编译器会翻译成*(arri)和*(iarr)结果一样这种写法了解即可指针访问数组效率更高编译器更易优化运行结果三.一维数组传参的本质先总结一下一维数组传参传的不是数组是首元素地址。所以函数形参里数组写法本质还是指针。3.1函数内无法计算数组长度举个例子#includestdio.hvoidtest(intarr[]){//sizeof(arr)是指针大小结果为1intsz2sizeof(arr)/sizeof(arr[0]);printf(sz2 %d\n,sz2);}intmain(){intarr[10]{1,2,3,4,5,6,7,8,9,10};intsz1sizeof(arr)/sizeof(arr[0]);printf(sz1 %d\n,sz1);test(arr);return0;}运行结果在这里sz2的值为2是因为我在vs2022编辑器里面用的是x64,说明在x64里面sz2的值为2如果我换成x86那么sz2的值就为1了注意函数内部绝对不能用sizeof求数组长度传参必须把数组长度一起传过去形参三种写法完全等价void test(int arr[])void test(int arr[10])void test(int* arr)四.冒泡排序指针 数组核心两两相邻元素比较交换逆序对进化版可提前终止有序数组。4.1基础版函数部分voidbubble_sort(intarr[],intsz){inti0;for(i0;isz-1;i){intj0;for(j0;jsz-i-1;j){if(arr[j]arr[j1]){inttmparr[j];arr[j]arr[j1];arr[j1]tmp;}}}}4.2进化版函数部分voidbubble_sort(intarr[],intsz){inti0;for(i0;isz-1;i){intflag1;//设一个flag当判断intj0;for(j0;jsz-i-1;j){if(arr[j]arr[j1]){flag0;inttmparr[j];arr[j]arr[j1];arr[j1]tmp;}}if(flag1)break;}}加了flag有序数组可以直接提前退出效率高很多。五.二级指针指针变量也是变量是变量就有地址存放指针地址的变量就是二级指针。一级指针int*-- 存放普通变量地址二级指针int**-- 存放一级指针地址三级指针int***-- 存放二级指针地址二级指针常用于动态二维数组、函数修改一级指针例如#includestdio.hintmain(){inta10;//一级指针:存放变量a的地址intb0;int*paa;//二级指针:存放一级指针pa的地址int**ppapa;*ppab;// 等价于pa b**ppa30;// 等价于a 30return0;}我们可以看到*ppa找到pa**ppa找到a六.指针数组指针数组是存放指针 (地址) 的数组。指针数组是数组里面每个元素是指针数组指针int(*p)[10]是指针指向整个数组区分口诀括号优先是指针括号靠后是数组举个例子#includestdio.hintmain(){inta10;intb20;intc30;int*parr[3]{a,b,c};return0;}定义int* parr[3]表示数组有3 个元素每个元素是int*类型指针。七.指针数组模拟二维数组指针数组可模拟二维数组效果但每行内存不连续。补充真实二维数组整段连续内存指针数组模拟每行独立不连续适用场景字符串数组、不规则行列数据举例#includestdio.hintmain(){intarr1[]{1,2,3,4,5};intarr2[]{2,3,4,5,6};intarr3[]{3,4,5,6,7};int*parr[3]{arr1,arr2,arr3};inti0,j0;for(i0;i3;i){for(j0;j5;j){printf(%d ,parr[i][j]);//i是哪一行数组j是数组第几个元素}printf(\n);}return0;}运行结果总结数组名默认是首元素地址仅sizeof(数组名)、数组名表示整个数组。数组访问本质是*(地址偏移量)指针与数组名可通用。一维数组传参传递首元素地址函数内不能用 sizeof 求长度。二级指针存储一级指针地址指针数组是存放指针的数组。指针数组可模拟二维数组但内存不连续。易错点混淆arr与arr导致指针偏移错误。函数内用sizeof(形参数组)计算长度结果错误。二级指针解引用层级错误*ppa与**ppa混用。把指针数组当成二维数组误以为内存连续。冒泡排序边界条件写错导致越界或漏排。如果这篇文章对友友们有帮助期待友友们的支持点赞 ❤️ 干货收藏助力指针吃透收藏 反复回看攻克难点盲区关注 持续更新C 语言不迷路留言 交流探讨学习共同进步友友们的每一次互动都是我持续更新C语言硬核知识的动力

更多文章