【C语言进阶】 数组指针与指针数组详解 与 数组传参和指针传参

一、指针数组

指针数组,顾名思义就是用来存放指针的数组。
下面是一些指针数组的简单例子。

int main()//诸如此类就是指针数组
{
	int a = 1, b = 2, c = 3, d = 4;
	int* pa[4] = { &a,&b,&c,&d };//数组元素为整型指针
	char* pch[10] = { 0 };//数组元素为字符指针
    int** Ppa = {0};//数组元素为二级指针
	return 0;
}

指针数组的应用:存放数组首元素地址。
我们知道,数组名为数组的首元素地址,我们可以创建一个数组Parr来存放其他数组名。

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 6,7,8,9,0 };
	int arr3[] = { 4,5,6,7,8 };
	int* Parr[] = {arr1,arr2,arr3};
	int i = 0, j = 0;
	for (i = 0; i < 3; i++)
	{
		for (j = 0; j < 5; j++)
		{
			printf("%d ", *(Parr[i] + j));
		}
		printf("\n");
	}
	return 0;
}

二、数组指针

(1). 数组指针的概念

数组指针,即数组的指针,指针指向的内容为数组·。

首先我们要明确,一个存放10个整型的数组arr[10],这个数组的数据类型为 int [10]

数组指针的定义方法 *int(p)[10] = &arr; p为数组指针;

(*p)外边的是指针指向对象的类型 int [10];
()内*p代表它是指针;
p是指针变量的名字;

下面我们上代码来展现数组指针:

int main()
{
	int* pa = NULL;       //pa 是整形指针 - 指向整形的指针 - 可以存放整形的地址
	char* pch = NULL;     //pch是字符指针 - 指向字符的指针 - 可以存放字符的地址
	                    //同理:数组指针 - 指向数组的指针 - 存放数组的地址
	                    
	//arr - 首元素地址
	//&arr[0] - 首元素地址
	//&arr - 数组的地址
	
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	
	int* p0 = arr;   //这是取数组首元素地址
	
	int(*p)[10] = &arr;    //数组指针p用int(*p)[10]表示,其中int[10]是数组的类型
	//若上述p的类型为int* p,就无法与整形指针区别;若int *p[10],[]的优先级比*高,先和[]结合,表示存放指针的数组;

	return 0;
}

(2). 对比数组指针与指针数组

①题目:

区分下面p1 p2是什么类型?
int *p1[10]
int(*p2)[10]

int *p1[10] ---- 存放指针的数组 – 指针数组
int(*p2)[10] — 指向数组的指针 – 数组指针 // p2的类型是 int(*)[10]

②题目:

pa为&arr,请写出pa的类型声明

int main()
{
	char* arr[5];
	return 0;
}

答案:char* (*pa)[5] = &arr;
(*pa)代表pa变量为指针;外面的char* [5]是指针指向对象的类型 。

③题目:

区分下面是什么 ?
注:做下面题目的核心思想为 [ ] 优先级比 * 高

  int *p                   //是一个指针,指向整形
  int arr[5]               //是一个5个元素的整形数组
  int *parr1[10]           //是一个数组,有10个元素,元素类型是int*,parr1是指针数组
  int (*parr2)[10]         //是一个指针,指向一个有10个整形元素的数组                                 //parr2的类型为 int(* )[10]
  int (*parr3[10])[5]      //是一个有10个元素的数组,每个元素是个数组指针,指向有5个整形元素的数组 

(3). 数组指针的简单应用

数组指针的简单应用

数组指针int(*p)[10]=&arr; *p的作用相当于arr

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int(*pa)[10] = &arr;
	int i = 0;
	
	for (i = 0; i < 10; i++)
	{
	    //用法1,arr[i]变成(*p)[i],相当于arr[i]
		printf("%d", (*pa)[i]);
	}
	
	for (i = 0; i < 10; i++)
	{
		//用法2,pa解引用为*pa,相当于arr,可以当首元素地址使用
		printf("%d", *(*pa + i));
	}
}

数组指针具体应用

我们直接上代码:
(下面代码的原理是:二维数组名 为 第一行的一维数组的地址)

void pri1(int ARR[3][3], int x, int y)//(参数的数组的形式)
{
	int i, j;
	for (i = 0; i < x; i++)
	{
		for (j = 0; j < y; j++)
		{
			printf("%d ", ARR[i][j]);
		}
		printf("\n");
	}
}


//二维数组int arr[3][3]传参,传的是(二维数组首元素)地址 ,是(一维数组)的地址,是int(*p)[3]
void pri2(int(*p)[3], int x, int y)//(参数是指针的形式)
{
	int i, j;
	for (i = 0; i < x; i++)
	{
		for (j = 0; j < y; j++)
		{
			             /因为p[i]是以p为首元素地址访问下标为i的元素 == *(p+i)
			             //所以可以写成下面几种形式
			printf("%d ", *(*(p + i) + j));
			printf("%d ", (*(p + i))[j]);
			printf("%d ", *(p[i] + j));
			printf("%d ", p[i][j]);   //相当于(p[i])[j] == (每行的数组名)[j]
		}
		printf("\n");
	}
}


int main()
{
	int arr[3][3] = { {1,2,3},{4,5,6},{7,8,9} };
	
	pri1(arr, 3, 3);//数组名传参,数组形式接收
	printf("\n");


	//arr -- 二维数组名 -- 首元素地址
	//二维数组的首元素是什么?
	//这里要把二维数组看作一维数组,每一行(每一个{})看作一个元素
	//那么arr[3][3]有三个元素,每一行是一个元素
	//那么{{1,2,3},{4,5,6},{7,8,9}}的首元素就是{1,2,3},是一维数组
	//二维数组数组名是首元素地址,就是第一行的地址,是一个一维数组的地址
	pri2(arr, 3, 3);
    printf("\n");

	return 0;
}

补充:下标引用操作符

下标引用操作符[]的本质 *(p + i)

p为指针,p[i]表示 – 以p为起始地址,访问下标为i的元素
p[i] == *(p + i)

int main()
{
	int arr[5] = { 1,2,3,4,5 };
	int* p = arr;
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);//数组名+下标引用操作符
		printf("%d ", *(arr + i));//数组首元素地址+下标,解引用
		printf("%d ", *(p + i));//和上一个一样
		printf("%d ", p[i]);//以p为起始地址,访问下标为i的元素
		 
		                  //由上面得出,p[i] == *(p + i)
		printf("\n");
	}
	return 0;
}

三、数组传参和指针传参

(1). 一维数组传参

传参时,可以在形参部分写【数组】或【指针】

void test1(int arr1[])//拿数组接收,可不写大小
{ }
void test2(int arr1[10])//拿数组接收
{ }
void test3(int *arr1)//拿指针接受
{ }
void Test1(int *arr2[20])//拿数组接收
{ }
void Test2(int **arr2)//拿指针接收
{ }
int main()
{
	int arr1[10] = { 0 };
	int* arr2[20] = { 0 };
	test1(arr1); test2(arr1); test3(arr1);
	Test1(arr2); Test2(arr2);
	return 0;
}

(2). 二维数组传参

void test1(int arr[3][5])//用数组来接收
{ }
void test2(int arr[][5])//二维数组行可以省略,列不可以省略
{ }
void test3(int(*arr)[5])//用二维数组的首元素地址(第一行一维数组的地址)来接收
{ }

int main()
{
	int arr[3][5] = { 0 };
	test1(arr);
	test2(arr);
	test3(arr);
	return 0;
}

(2). 一级指针传参

void test(int *p)//用指针接收
{ }
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,0 };
	int x = 10;
	int* pa = arr;
	int* px = &x;
	test(pa);      //可传 指针变量
	test(arr);     //可传数组首元素地址
	test(px);      //可传指针变量
	test(&x);      //可传变量地址
	return 0;
}

(4). 二级指针传参

void test(int** p)//用二级指针接收
{ }
int main()
{
	int* arr[10];
	int** pa = arr;
	int n = 10;
	int* p = &n;
	int** Pp = &p;
	test(Pp);      //可传二级指针变量
	test(&p);      //可传一级指针的地址
	test(arr);     //可传指针数组首元素地址
	test(pa);      //可传二级指针变量
	return 0;
}
  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值