深入了解指针(6)
1.数组指针变量概念
指针数组:
是数组,是存放指针的
数组指针:
是指针,指向数组的指针
所以,数组指针变量应该是:存放数组的地址,能够指向数组的指针变量
思考⼀下:p1,p2分别是什么?
2.数组指针变量初始化
数组指针变量是⽤来存放数组地址的,那怎么获得数组的地址呢?就是我们之前学习的 & 数组名 。
扩展一下:
分析如下:
+1跳过一个整型
+1跳过整个数组
理解这点有什么用呢?
看两段代码
虽然第二段也可以运行出来,但是,这是不好的示范。
3.⼆维数组传参的本质
有了数组指针的理解,我们就能够讲⼀下⼆维数组传参的本质了。 过去我们有⼀个⼆维数组的需要传参给⼀个函数的时候,我们是这样写的:
这里实参是⼆维数组,形参也写成⼆维数组的形式。
⾸先我们再次理解⼀下⼆维数组,⼆维数组起始可以看做是每个元素是⼀维数组的数组,也就是⼆维 数组的每个元素是⼀个⼀维数组。那么⼆维数组的⾸元素就是第⼀⾏,是个⼀维数组。 如下图:
补充:
二维数组的数组名也是数组首元素的地址,到底是谁的地址,其中首元素应该如何解读呢?
二维数组有很多行,其中一横行就可以看作是一个一维数组。
所以:
首元素就是第一行
首元素的地址就是第一行的地址
第一行的地址就是一维数组的地址
类型是数组指针类型
所以,根据数组名是数组⾸元素的地址这个规则,⼆维数组的数组名表⽰的就是第⼀⾏的地址,是⼀维数组的地址。根据上⾯的例⼦,第⼀⾏的⼀维数组的类型就是int [5] ,所以第⼀⾏的地址的类型就是数组指针类型int(*)[5] 。那就意味着⼆维数组传参本质上也是传递了地址,传递的是第⼀⾏这个⼀维数组的地址,那么形参也是可以写成指针形式的。
看看接下来的代码:
此时二维数组传参,形参被形成了指针的形式。
其中可以把二维数组看作一维数组,一层一层的看
所以,⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。
本篇中所用到的代码如下所示:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
//int main()
//{
// int a = 10;
// int* pa = &a;
// //整型指针
// char ch = 'w';
// char* pc = &ch;
// //字符指针
// int arr[10] = { 0 };
// //p = &arr;
// //p变量中储存数组的地址,所以p是一个数组指针变量
// //取出的是数组的地址
// //arr —— 数组首元素的地址
//
// int* p1[10];
// //p1是指针数组 — 存储指针的数组
// int(*p2)[10];
// //p2是指针变量,指向的是数组 — 数组指针
// return 0;
//}//int main()
//{
// int arr[10] = { 0 };
// int* p1 = arr;
// //p1、arr类型如下:
// // int* int*
// printf("%p\n", p1);
// printf("%p\n", p1+1);
// //+4
// int (*p2)[10]= &arr;
// //p2类型如下:
// //int (*)[10]
// printf("%p\n", p2);
// printf("%p\n", p2+1);
// //40
// return 0;
//}//int main()
//{
// int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
// int* p = arr;
// int i = 0;
// for (i = 0; i < 10; i++)
// {
// printf("%d\n", *p);
// p++;
// }
// return 0;
//}//int main()
//{
// int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
// int(*p)[10] = &arr;
// //& * 两个可以抵消
// //*&arr == arr
// int i = 0;
// for (i = 0; i < 10; i++)
// {
// printf("%d ", (*p)[i]);
// }
// return 0;
//}二维数组传参之前写法
//print(int arr[3][5], int r, int c)
//{
// int i = 0;
// for (i = 0; i < r; i++)
// {
// int j = 0;
// for (j = 0; j < c; j++)
// {
// printf("%d ", arr[i][j]);
// }
// printf("\n");
// }
//}
//
//int main()
//{
// int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };
// print(arr, 3, 5);
//
// return 0;
//}二维数组传参之前写法
//print(int arr[3][5], int r, int c)
//{
// int i = 0;
// for (i = 0; i < r; i++)
// {
// int j = 0;
// for (j = 0; j < c; j++)
// {
// printf("%d ", arr[i][j]);
// }
// printf("\n");
// }
//}void print(int (*arr)[5], int r, int c)
{int i = 0;for (i = 0; i < r; i++){int j = 0;for (j = 0; j < c; j++){printf("%d ", *(*(arr + i) + j));//*(arr + i)等价于arr[i]}printf("\n");}
}int main()
{int arr[3][5] = { {1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7} };//一般情况下,数组名是数组首元素的地址,特殊的://1. &数组名//2.sizeof(数组名)print(arr, 3, 5);return 0;
}