知识重复
-
变量指针:变量最小的地址值(首地址),本质是地址、指针
-
指针变量:存储指针的变量,本质是变量
-
&:取地址运算符(取址符、取地址符),获取变量、数组等的地址
-
*:指针操作符,如果这个符号前面有数据类型,就被称为“指针声明符”,如果没有数据类型,就被称为“解引用符”
-
指向:指针变量存储了谁的地址,这个指针变量就指向了谁
-
交换指向:指向发生改变,指向对象的数据不会改变
-
交换数据:指向不发生改变,指向对象的数据会改变
-
指针变量本质上还是变量,只不过指针变量只能存储其他内存单元的地址,我们借助于指针变量,就能实现内存空间的共享
-
共享他人空间:
int a = 10; int *p = &a; int *q = p;
-
共享自己的空间:
int a = 10; int *p = &a; //a和p共享a的空间
指针数组和数组指针
数组指针
定义
- 概念:数组指针是指向数组的指针(指针变量),本质上还是指针
指针变量指向数组元素和数组指针的区别:
特点
- ①先有数组,再有指针
- ②它指向的是一个完整的数组
一维数组指针
语法
数据类型 (*指针变量名)[容量];
案例
我们之前所学的是指向数组元素的指针,本质上是指针变量;现在我们学的是指向数组的指针,叫做数组指针
二维数组指针
语法:
数据类型 (*指针变量名)[行容量][列容量];
案例1
//写法1:二维数组指针指向二维数组----不推荐
#include <stdio.h>
int main()
{//创建一个二维数组int arr[][3] = {10,20,30,100,200,300,1000,2000,3000};//定义一个二维数组指针指向二维数组int (*p)[][3] = &arr;//遍历数组for(int i = 0;i < 3; i++){for(int j = 0;j < 3; j++){printf("%-6d",(*p)[i][j]);}}printf("\n");//写法2:一维数组指针指向二维数组-----推荐//创建一个二维数组int arr[][3] = {10,20,30,100,200,300,1000,2000,3000}; //定义一个一维数组指针指向二维数组,相当于指针指向的是二维数组的行[行容量]int (*p)[3] = arr;//等价于&arr[0] (*p):指向数组的行 int arr[] = {100,200,300}; int *p = arr; 解引用p得到第一个元素//遍历数组for(int i = 0;i < 3; i++){for(int j = 0;j < 3; j++){printf("%-6d",(*p)[i][j]);}}printf("\n"); return 0;
}
案例2
/*
**指向一维数组的指针
*/#include <stdio.h>int t_pl()
{//创建一个一维数组int arr[] = {10,20,30,40,50};//计算数组大小int len = sizeof(arr) / sizeof(arr[0]);//创建一个数组指针指向一维数组arrint (*p)[len] = &arr;//借助数组指针遍历数组for(int i = 0; i < len; i++){//p 指向数组arr,p存储了数组arr的地址,如果要通过指针访问数组,就要对地址解引用(*p), *和[]在一起,[]的优先级大于*printf("%-4d", (*p)[i]);}printf("\n");
}/*
**指向二维数组的指针
*/int t_p2()
{//创建一个二维数组int arr[][3] = {{10,20,30},{100,2200,300},{1000,2000,3000}};//获取行和列的容量int row_len = sizeof(arr) / sizeof(arr[0]);int col_len = sizeof(arr[0]) / sizeof(arr[0][0]);//方式1(不推荐) 二维数组指针指向二维数组int (*p)[][3] = &arr;//遍历数组for(int i = 0;i < row_len; i++){for(int j = 0; j < col_len; j++){printf("%-6d", (*p)[i][j]); } }printf("\n");//方式2(推荐) 一维数组指针指向二维数组,本质上是一维数组指针指向二维数组的行(默认首行)//&arr:获取该二维数组的地址,范围作用于整个数组//arr:数组名,默认指向第一个元素,这个就是行,默认首行,范围作用于整个行,等价于&arr[0]//数组参与指针运算,会降级为指针int (*p1)[3] = &arr[0];for(int i = 0; i < row_len;i++){for(int j = 0; j < col_len; j++){printf("%-6d", p1[i][j]);printf("%-6d", (*(p1+i))[j]);printf("%-6d", *(p1[i]+j));//列偏移printf("%-6d", *(*(p1+i)+j));}}printf("\n");
}int main()
{return 0;
}
数组指针和指针数组
数组指针
指针和数组中符号优先级
() > [] > *
通过指针引用二维数组
int arr[][] = {{2000},{},{}};
表示形式 | 含义 | 地址/值 |
---|---|---|
arr | 二维数组名,指向一维数组的arr[0],0行首地址 | 2000 |
arr[0],*****(arr + 0),*arr | 0行0列元素地址,数组降级指针 | 2000 |
arr + 1,&arr[1] | 1行首地址 | 2008 |
arr[1],*(arr + 1) | 1行0列元素a[1] [0]的地址 | 2008 |
arr[1]+2,*(arr + 1)+2,&arr[1] [2] | 1行2列元素a[1] [2]的地址 | 2012 |
* (a[1]+2), * (* (arr+1)+2),arr[1] [2] | 1行2列元素a[1] [2]的值 | 元素值为13 |
注意:二维数组中,数组整体的地址值 == 数组中0行元素的地址值 == 数组中0行0列元素的地址值
案例1
-
用指向元素的指针变量输出二维数组元素的值
#include <stdio.h>int mian() {//定义一个二维数组int arr[3][4] = {10,20,30,40,100,200,300,400,1000,2000,3000,4000};//定义一个指针变量,用来指向数组中的元素int *p = arr[0];//获取元素个数 行容量 * 列容量int len = (sizeof(arr) /sizeof(arr[0])) * (sizeof(arr[0]) / sizeof(arr[0][0]));//使用单层for循环遍历二维数组,列偏移for(; p < arr[0] + len; p++){//每四个一行 if((p - arr[0]) % 4 == 0 && p != arr[0])printf("\n"); printf("%-6d", *p); }printf("\n");return 0; }
案例2
-
数组指针输出二维数组任意行任意列的元素的值
指针数组
-
定义:指针数组是一个数组,数组中每一个元素都是一个指针。
-
特点:
- 先有指针,后有数组
- 指针数组的本质是一个数组,只是数组中的每一个元素是指针
-
语法:
数据类型 *数组名[容量];
案例
#include <stdio.h>int main()
{//定义三个变量int a = 10, b = 20, c = 30;//定义指针数组:先有指针,后有数组、int *arr[3] = {&a, &b, &c};//获取大小int len = sizeof(arr) / sizeof(arr[0]);//遍历数组for(int i = 0; i < len; i++){printf("%-3d", *arr[i]); }printf("\n");return 0;
}
- 建议:我们一般使用指针数组处理字符串,后续专门讲解
数组指针与指针数组的区别
对比项 | 指针数组 | 数组指针 |
---|---|---|
定义 | 数组元素均为指针的数组 | 指向一个完整数组的指针 |
存储内容 | 存储多个指针,每个元素指向不同的内存地址 | 存储单个指针,指向一个完整的数组(首地址) |
内存分配 | 每个指针元素独立分配内存,可能分散 | 指向的数组内存连续的,指针本身存储数组首地址 |
语法实例 | int *arr[5] 元素为5个int *指针 | int (*arr) [5] 指向5个int的数组的指针 |
访问方式 | 通过下标访问指针元素,再解引用 *arr[i] | 先解引用指针得到数组,再访问元素 (*arr) [i] |
使用场景 | 管理多个独立指针(如字符串数组、动态结构体数组) | 操作多维数组(如传递二维数组的行指针) |
内存布局 | [ptr1] --> 数据1 [ptr2] --> 数据2 … | ptr --> [数据1] [数据2]… |
示例代码 | int a = 1,b = 2;int *arr[] = {&a,&b}; | int arr[2] [3] = {1,2,3,4,5,6};int (*ptr)[3] = arr; |