指针数组,数组指针,函数指针,函数指针数组,函数指针数组的指针

首先我们来看一下它们分别的定义方式:

指针数组:int* p[5];
数组指针:int (*p)[5];
函数指针:int (*p)(int,int);
函数指针数组:int(p[5])(int x, int y);
函数指针数组的指针:int (
(*p)[5])(int x,int y);

指针数组是数组,是一个存放指针的数组
数组指针是指针,是一个指向数组的指针
函数指针是指针,是一个指向函数的指针
函数指针数组是数组,是一个存放函数地址的数组
函数指针数组的指针是指针,是一个指向 函数指针数组 的指针

关于优先级的问题:
[] 的优先级高于 * ,而 ()的优先级高于[] 。

一、指针数组:
int* p[5] ,[]的优先级比较高,因此[]和p先结合,因此p是(int*)类型的,是一个整型指针的数组。
我们来看一段代码:

  	int a=1,b=2;
	int *p[2]; //定义指针数组
	p[0]=&a; //给数组第一个元素赋值为a的地址
	p[1]=&b; //给数组第二个元素赋值为b的地址
	printf("p[0]=%p,  &a=%p\n",p[0],&a); //输出第一个数组第一个元素,与a地址比较
	printf("p[1]=%p,  &b=%p\n",p[1],&b);
	printf("*p[0]=%d, a=%d\n",*p[0],a); //输出数组第一个元素的值
	printf("*p[1]=%d,b=%d\n",*p[1],b);

运行结果:
在这里插入图片描述
我们可以看到:p[0],p[1]输出的结果是两个地址,*p[0] 和 p[1] 是两个整数,因此指针数组存放的是地址,这里定义的intp[2],就只能存放int类型的数据的地址。
—>>指针数组还有一个很重要的用处就是用来指向 二维数组的第一维,为什么呢?因为指针数组的本质是数组,数组中的元素是指针类型,而二维数组中的第一维是一维数组的首地址,类型匹配可以用指针类型指向。

int a[2][3]={{1,2,3},{4,5,6}};
    int i,j;
    int *p[2];
    p[0]=a[0];
    p[1]=a[1];
    for(i=0;i<2;i++)
    {
        for(j=0;j<3;j++,p[i]++)
            printf("%3d",*p[i]);
        printf("\n");
    }
    return 0;

在这里插入图片描述
二、数组指针
int (*p)[5] ,()的优先级比[]的优先级高,所以p先与 * 结合,因此p是一个指针,而这个指针指向了int类型的长度为5的一个数组,它就是整型数组的指针。(int (*p)[5],我们不妨将它写成 int[5]*p是不是就更好理解了呢,这样表示可以帮助我们理解,但是编译不能这样写,因为编译器不认识。)

int main(){
int arr[4] = {0};
arr;//表示数组首元素的地址
&arr;//表示数组的地址
// 具 体 差 异 在 哪 ? ?
 printf("arr=%p\n", arr);
 printf("&arr=%p\n",&arr);
 printf("arr+1=%p\n", arr+1);
 printf("&arr+1=%p\n", &arr+1);
//我们可以看出产生的结果是截然不同的

//这是因为数组的地址和数组首元素的地址值是相同的,但是意义不同。
int (*p)[4];
//p是int类型的数组的指针,存放数组地址,那么
//p=arr; //会报错
p=&arr;
printf("p=%p\n",p);
printf("p+1=%p\n",p+1);
return 0;
}

运行结果:
在这里插入图片描述
在这里我们可以看到,arr和&arr表示的地址是一样的,但是+1的结果却有不同,这是因为,arr表示数组首元素的地址,而&arr表示的是数组的地址,arr+1则表示第二个元素的地址,增加int类型的4个字节,而&arr+1,整个数组的地址加一,总共4个元素,4*4=16个字节。在16进制中,0018FF38+16=0018FF48。
int (*p)[4],定义了了一个指向int类型的长度为4的 指针变量,这里赋值只能将&arr也就是整个数组的地址给它,当赋值p=arr时,程序会报错,也正是因为,p存放的整个数组的地址,而arr只表示首元素的地址。p+1的值与&arr+1的值也就相同。

我们再来看一段代码:

int array[2][3] =
{
	{ 0, 1, 2 },
	{ 3, 4, 5 } 
};

//指针数组
int *p[2][3];
//用了两层for循环遍历这个二维数组,将数组每个元素的地址赋给指针数组的每一个元素
for (int i = 0; i < 2; i++)
{
	for (int j = 0; j < 3; j++)
	{
		p[i][j] = &array[i][j];
	}
}
//遍历指针数组 *p[i][j] 输出数组p中每个元素的值
for ( i = 0; i < 2; i++)
{
	for (int j = 0; j < 3; j++)
	{
		printf("%d ", *p[i][j]);
	}
	printf("\n");
}

//数组指针
int (*q)[3] = array;
for ( i = 0; i < 2; i++)
{
	for (int j = 0; j < 3; j++)
	{
		printf("%d ", q[i][j]);
	}
	printf("\n");
}
return 0;
}

运行结果:
在这里插入图片描述
同样是二维数组赋值并输出,指针数组却用了两次两层的for循环,第一次将原二维数组的地址赋给指针数组的每个元素,第二次是取地址的的值将其循环输出。
然而,定义的数组指针却能够通过int (*q)[3] = array;就获得原二维数组的值,这是因为我们将array[2][3]看作一个2个具有三个元素的一维数组,这里的array表示的是第一行元素的地址,相当于一个一维数组,因此能够直接赋值给p。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值