指针进阶II · 指针数组和数组指针

举报
安然无虞 发表于 2022/05/26 22:53:23 2022/05/26
【摘要】 大家好,我是安然无虞。 文章目录 一、指针数组补充易错点 二、数组指针补充易错点 三、遇见安然遇见你,不负代码不负卿。 一、指针数组 指针数组,顾名思...

大家好,我是安然无虞。

一、指针数组

指针数组,顾名思义就是存放指针的数组

看看下面这些类型的数组

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

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。