数组指针
(1)、定义
-
概念:数组指针是指向整个数组的指针,本质上还是指针(地址)
-
特点:
-
先有数组,后有指针
-
它指向的是一个完整的数组
-
(2)、一维数组指针
-
语法:(必须给*指针变量名带括号,
[]
的优先级高于*
)数据类型 (*指针变量名)[数组容量];
-
案例:
int arr[] = {11, 22, 33, 44, 55};int *p = arr; //这里是指向数组的首地址p++; //可以进行自增操作,指向首元素的下一个元素//对数组指针 不要随意使用自增操作,不然会下标越界,成为野指针(指向一处未知区域)
//数组指针:指向数组的指针(这里是指向整个数组,不是数组的某个元素)int main(){//一维数组指针//先有数组,再有指针//指针不能独立存在,必须依赖与现有的常量或者变量空间int arr[] = {100, 200, 300};//获取数组的大小int len = sizeof(arr) / sizeof(arr[0]);//指针变量指向数组元素:此时指针指向的是数组中的第一个元素,此时指针存储的值是首元素的地址值int *q = arr;//定义一个数组指针/////数组指针指向整个数组:此时指针指向的是整个数组,此时指针存储的值是首元素的地址值int (*p)[len] = &arr; //数组名和&在一起就代表整个数组的地址,数组名单独出现就代表的数组首元素的地址//此时不能p++,否则会下标越界,产生野指针printf("%p, %p, %p\n", p, &arr, arr); //结果一样,指向的都是数组元素首地址如何访问数组指针//printf("%d\n", (*p)[0]); //100//遍历数组指针for(int i = 0; i < len; i++){printf("%-4d", (*p)[i]); //数组指针本质是指针所以我们需要添加小括号提升指针的优先级(默认数组优先)}}
-
我们之前所学的是指向数组元素的指针,本质上是指针变量,现在我们学的是指向数组的指针,叫做数组指针
-
注意:
-
指针变量指向数组元素:此时指针指向的是数组中的第一个元素,此时指针存储的值是首元素的地址值 int *q = arr;
-
数组指针指向整个数组:此时指针指向的是整个数组,此时指针存储的值是首元素的地址值 int (*p)[len] = &arr;
-
arr默认指向首元素,&arr指向整个数组
-
(3)、二维数组指针
-
语法:
数据类型 (*指针变量名)[行容量][列容量];
-
案例:
-
写法1:不推荐
int arr[][3] = {10, 20, 30, 100, 200, 300, 1000, 2000, 3000};//定义一个数组指针指向二维数组arrint (*p)[][3] = &arr; //数组指针指向二维数组,不推荐
-
写法2:推荐
int arr[][3] = {10, 20, 30, 100, 200, 300, 1000, 2000, 3000};定义一维数组指针/int (*p)[3] = arr; //数组指针指向二维数组首行,推荐,默认指向第一行//p++; //可以进行p++,加一次就往下指一行///遍历方法1(指针数组方式)/for(int i = 0; i < 3; i++){for(int j = 0; j < 3; j++){printf("%-5d", p[i][j]); //arr的地址等于p存储的地址,也就意味着p等价于arr} printf("\n");}/遍历方法2(数组指针解引用)for(int i = 0; i < 3; i++){for(int j = 0; j < 3; j++){printf("%-5d", *(*(p + i) + j)); //先偏移行再偏移列。*(p+i) → p[i], *(p[i] + j) → p[i][j]}}printf("\n");//遍历方法3(混合法)///for(int i = 0; i < 3; i++){for(int j = 0; j < 3; j++){printf("%-5d", (*(p + i))[j]); }}}
-
(4)、指针和数组中符号优先级
()
>[]
>*
(5)、通过指针引用二维数组
表示形式 | 含义 |
---|---|
a | 二维数组名,相当于&a[0],指向一维数组a[0](0行首地址) |
a[0]、*(a+0)、 *a | &a[0] [0].0行0列元素地址 |
a+1、&a[1] | 1行首地址 |
a[1]、*(a+1) | &a[1] [0].1行0列元素的地址 |
a[1]+2、&a[1] [2]、*(a+1)+2 | 1行2列元素的地址 |
*(a[1]+2)、 *( *(a+1)+2)、a[1] [2] | 1行2列元素a[1] [2]的值 |
-
注意:二维数组中,数组整体的地址值 == 数组中0行元素的地址值 == 数组中0行0列元素的地址值
(6)、案例
-
案例1:最简单的方法
-
需求:用指向元素的指针变量输出二维数组元素的值
-
代码:
//定义一个普通的二维数组int arr[3][4] = {10, 20, 30, 40, 100, 200, 300, 400, 1000, 2000, 3000, 4000};//定义一个指针变量,用来接收二维数组的元素int *p = arr[0]; //列 10 的位置//获取元素个数//int len = (sizeof(arr) / sizeof(arr[0])) * (sizeof(arr[0]) / sizeof(arr[0][0]));int len = sizeof(arr) / sizeof(arr[0][0]);//遍历数组//for(; p < arr + sizeof(arr) / sizeof(arr[0]); p++) //会报警告,不影响使用for(; p < arr[0] + len; p++){printf("%-6d", *p);//每四个换行if((p - arr[0]) % 4 == 0 ) //p2-p1 = nprintf("\n");}printf("\n");
-
-
案例2
-
需求:数组指针-输出二维数组任一行任一列元素的值
-
代码:
#include <stdio.h>/*** 需求:数组指针-输出二维数组任一行任一列元素的值*/void arr_fun2(){//定义一个二维数组int arr[3][4] = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23};//创建一个一维的数组指针指向一个二维的数组int (*p)[4] = arr; //等价于&arr[0],p代表我们这个二维数组//创建两个变量,代表我们对应数据的行和列int row, col;//通过控制台来输入printf("请输入行号和列号:\n");scanf("%d, %d", &row, &col);printf("arr[%d][%d] = %d\n", row, col, *(*(p + row) + col)); //*(*(p + row) + col) → *(p[row]+col) → p[row][col]}int main(){arr_fun2();return 0;}
-
2、指针数组
(1)定义
-
概念:指针数组是一个数组,数组中的每一个元素都是一个指针
-
特点:
-
先有指针,后有数组
-
指针数组的本质是一个数组,只是数组中的元素类型是指针
-
-
语法:
数据类型 *数组名[容量];
-
案例:
//定义三个变量int a = 10, b = 20, c = 30;//定义指针数组,指针数组是用来存储指针的int *arr[3] = {&a, &b, &c}; //int是abc的类型//指针数组里的元素不要直接用,因为是地址,如果要使用的话要先解引用//获取数组大小int len = sizeof arr / sizeof arr[0];//sizeof和return是运算符,可以带括号也可以不带//遍历数组for(int i = 0; i < len; i++){printf("%-3d", *arr[i]);}printf("\n");
-
建议:我们一般使用指针数组处理字符串
3、数组指针与指针数组的区别
对比项 | 指针数组 | 数组指针 |
---|---|---|
定义 | 数组元素均为指针的数组 | 指向一个数组的指针 |
存储内容 | 存储多个指针,每个元素指向不同内存地址 | 存储单个指针,指向一个完整的数组(首地址) |
内存分配 | 每个指针元素独立分配内存,可能分散 | 指向的数组内存连续,指针本身存储数组首地址 |
语法示例 | int *arr[5];(元素为5个int类型的指针) | int (*ptr)[5];(指向含5个int元素的数组的指针) |
访问方式 | 通过下标访问指针元素,再解引用:*arr[i] | 先解引用指针得到数组,再访问元素:(*ptr)[i]或ptr[0] [i] |
使用场景 | 管理多个独立指针(如字符串数组、动态结构体数组) | 操作多维数组(如传递二维数组的行指针) |
示例代码 | int a = 1, b = 2; int *arr[] = {&a, &b}; | int arr[2] [3] = {1, 2, 3, 4, 5, 6}; int (*ptr)[3] = arr; |