指针进阶II · 指针数组和数组指针
大家好,我是安然无虞。
一、指针数组
指针数组,顾名思义就是存放指针的数组
看看下面这些类型的数组:
int* arr1[10];//整型指针的数组
char* arr2[5];//一级字符指针的数组
char** arr3[5];//二级字符指针的数组
- 1
- 2
- 3
- 4
- 5
下面给出一道指针数组的小例题:
#include<stdio.h>
int main()
{
char* arr[] = { "abcdef", "qwer", "zhangsan" };
int sz = sizeof(arr) / sizeof(arr[0]);
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%s\n", arr[i]);
}
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
很简单,这里就不过多阐述了。
补充易错点
&数组名和数组名:
之前有提到过这部分概念,所以在这里就不过多赘述了,直接给出下面结论:&数组名表示取出整个数组的地址;数组名表示数组首元素的地址。,因为 &数组名+1 跳过整个数组,数组名+1 却仅仅跳过一个首元素(这里细细体会一下)。
二、数组指针
问:数组指针是数组还是指针?
答案:数组指针是指针,是能够指向数组的指针。
试分析以下代码:
int* p1[10];//p1是存放10个整型指针的数组
int(*p2)[10];//p2先和'*'结合,说明p2是一个指针,指向的是一个数组,数组有10个元素,每个元素类型是int,所以p2是一个数组指针
- 1
- 2
- 3
这里的话我就直接把答案给出来了,不过需要注意的是:[ ] 的优先级要高于 * 的,所以在写数组指针的时候必须加上 () 来保证 p2 先和 * 结合。
为了强化理解上述概念,做了如下补充:
char arr[5];
char(*pa)[5] = &arr;//pa先和*结合,说明pa是一个指针,看到'[]'说明指向一个数组,数组有5个元素,每个元素类型是char,所以pa的类型就是char(*)[5]
int* parr[6];
int*(*pa)[6] = &parr;//pa类型是int*(*)[6]
- 1
- 2
- 3
- 4
- 5
到这里还是得探讨一下,数组名arr 和&数组名&arr 的本质是什么?
int arr[10];
//arr类型是int*(整型指针)
//&arr类型是int(*)[10](数组指针)
- 1
- 2
- 3
既然数组指针指的是数组,那么数组指针中存放的就是数组的地址。
问:数组指针是怎么使用的呢?
请看下列代码:
#include<stdio.h>
void print_arr1(int arr[3][5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
void print_arr2(int(*arr)[5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
int j = 0;
for (j = 0; j < col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
//*(arr+i)相当于二维数组第i行的数组名(可以这么去理解:*和&相抵消)
//数组名相当于数组首元素的地址,其实也就是第i行第一个元素的地址
//*(*(arr + i) + j)
//(arr + i) 相当于 第i行数组的地址
//*(arr + i) 相当于 第i行数组名,也就是第i行首元素的地址
//(*(arr + i) + j) 相当于 第i行第j列元素的地址
//*(*(arr + i) + j) 相当于 第i行第j列的元素
int main()
{
int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
print_arr1(arr, 3, 5);
print_arr2(arr, 3, 5);
//数组名arr表示首元素的地址
//但是二维数组的首元素跟一维数组不同,二维数组的首元素是第一行
//所以这里传递的arr,其实相当于第一行的地址,属于一维数组的地址
//所以可以用数组指针接收
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
学完数组指针和指针数组,分析下列代码:
int arr[5];//arr是一个数组,数组有5个元素,每个元素是int类型
int* parr1[10];//parr1是一个数组,数组有10个元素,每个元素类型是int*
int(*parr2)[10];//parr2是一个指针,指向一个含有10个元素,元素类型是int的数组,所以parr2是一个数组指针
int(*parr3[10])[5];
//parr3先和[]结合,说明parr3是一个数组,数组有10个元素,每个元素的类型是int(*)[5]的指针,该指针指向一个含有10个整型元素的数组
//所以parr3是一个数组指针数组
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
好,说到这里再啰嗦一下,对数组指针做一个总结:
int arr[10];
int* p = arr;
int(*p2)[10] = &arr;//取出的是整个数组的地址,既然是数组的地址
//就应该放到数组指针里面去,所以p2就是一个数组指针
//对p,p2进行分析:
//p中存放的是首元素的地址
//p+1跳过一个int
//*p访问一个int数据-4个字节,*p等价于首元素
//p2存放的是arr数组的地址
//p2+1跳过整个数组
//*p2访问的是arr数组,*p等价于arr(可以理解为&和*抵消了)
//那么*p2就是数组名了,所以*p2本质就是arr数组首元素的地址
//p <=> *p2 <=> arr
//p+1 <=> *p2 + 1
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
补充易错点
我们在写代码的时候难免要把【数组】或者【指针】传递给函数,那么函数的参数应该怎么设计呢?
一维数组传参
#include<stdio.h>
void test(int arr[]);//ok - 数组传参时,形参部分不会真的创建一个数组,写成数组是为了方便我们理解,写成指针才是本质
void test(int arr[10]);//ok
void test(int* arr);//ok
void test2(int* arr[20]);//ok
void test2(int** arr);//ok
int main()
{
int arr[10] = { 0 };
int* arr2[20] = { 0 };
test(arr);//数组名相当于首元素的地址
test2(arr2);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
一维数组传参比较简单,在这里的话就不过多赘述了,下面看看二维数组传参
二维数组传参
#include<stdio.h>
void test(int arr[3][5]);//ok
void test(int arr[][]);//这种写法是错误的,因为二维数组传参行可以省略,但是列不能省略
//因为列表示一行有几个元素,如果不知道一行有几个元素,那么这一行访问完了,不知道下一行在哪(细品)
void test(int arr[][5]);//ok
void test(int* arr);//这种写法是错误的,形参部分应该用数组指针接收
void test(int* arr[5]);//这种写法是错误的,误写成指针数组了
void test(int(*arr)[5]);//ok
void test(int** arr);//错错错
int main()
{
int arr[3][5] = { 0 };
test(arr);//数组名表示首元素的地址,二维数组的首元素是第一行,所以二维数组的数组名表示的是第一行的地址
//故而形参部分需要用数组指针接收
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
一级指针传参
#include<stdio.h>
//一般实参是一级指针的时候,形参写成一级指针即可,不需要写成数组的形式
void print(int* arr, int n)
{
int i = 0;
for (i = 0; i < n; i++)
{
printf("%d ", arr[i]);
}
printf("\n");
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9 };
int* p = arr;
int sz = sizeof(arr) / sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
思考题:
当一个函数的形参是一级指针的时候,函数能接受什么参数?
比如下面的test函数:
void test(int* p);
- 1
问:test函数能接收什么参数?
大家一定要想清楚,如果给你这么一个函数,我们可以把什么样的参数给它传过去,因为这点很重要!
请看:
int a = 10;
int* ptr = &a;
int arr[10] = {0};
test(&a);
test(ptr);
test(arr);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
二级指针传参
#include<stdio.h>
void test(int** ptr)
{
printf("num = %d\n", **ptr);
}
int main()
{
int n = 10;
int* p = &n;
int** pp = &p;
test(&p);
test(pp);
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
思考题:
当一个函数的形参是二级指针的时候,函数能接受什么参数?
比如下面的test2函数:
void test2(char** p);
- 1
请看:
char ch = 'w';
char* pc = &ch;
char** ppc = &pc;
char* arr[10] = {0};
test(&pc);
test(ppc);
test(arr);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
三、遇见安然遇见你,不负代码不负卿。
文章来源: bit-runout.blog.csdn.net,作者:安然无虞,版权归原作者所有,如需转载,请联系作者。
原文链接:bit-runout.blog.csdn.net/article/details/123170007
- 点赞
- 收藏
- 关注作者
评论(0)