一.指针数组
指针数组是存放指针的数组,首先得是一个数组,其次数组里的元素是指针。
所以数组名先和方括号 [ ] 结合 ,然后才是指针;
具体如下图:
实例:
代码语言:javascript
复制
int main()
{
int a[5] = { 1,2,3,4,5 };
int b[5] = { 5,6,7,8,9 };
int* parr[2] = { a,b };
int i = 0, j = 0;
for (i = 0; i < 2; i++)
{
for (j = 0; j < 5; j++)
{
printf("%d ", *(parr[i] + j)); //parr[i] 就是数组parr 中下标为i的元素
} //该元素为数组名,数组名是数组首元素的地址
printf("\n"); //加上 j 就是数组中下标为 j 的元素的地址
} //对其解引用就得到了该元素
return 0;
}
当然上面代码中的 printf 语句还可以写成 printf("%d ",arr[i][j]);
运行结果:
二.数组指针
是指针,该指针指向的是一个数组,其中存放的是数组的地址。
也就是说它首先得是 一个指针,然后再说明它所指向的是一个数组
具体如下图:
操作符优先级详解见:http://t.csdn.cn/mnrSk
当然数组指针一般不用于一维数组中,通常应用在二维数组及更高维的数组中
例:
代码语言:javascript
复制
void print(int(*parr)[5], int row,int col)
{
int i = 0, j = 0;
for (i = 0; i < row; i++)
{
for (j = 0; j < col; j++)
{
printf("%d ", *(*(parr+i) + j)); //*(parr+i)表示数组 arr 第i行的地址
} //加上j表示第i行的第j个元素的地址
printf("\n"); //对其解引用就找到了这个元素
}
}
int main()
{
int arr[2][5] = { 1,2,3,4,5,6,7,8,9,10 };
print(arr, 2,5);
return 0;
}
运行结果:
三. 数组名 vs & 数组名 (arr vs &arr)
1.数组名和&数组名的值是一样的;
2.数组名和&数组名的意义不同。
请看代码:
代码语言:javascript
复制
int main()
{
int arr[5]={1,2,3,4,5};
printf("arr=%p\n",arr);
printf("&arr=%p\n\n",&arr);
printf("arr+1=%p\n",arr+1);
printf("&arr+!=%p\n",&arr+1);
return 0;
}
打印结果:
这是为什么呢?
1.因为&arr 取出的是整个数组的地址,而数组的地址也是从首元素的地址开始的,数组名表示数组首元素的地址,所以打印时 arr 和 &arr 的值相同;
2.arr+1所加的其实是1个步长,步长是由数组类型决定的,arr 的类型是 int ,+1表示跳过4个字节,所以 arr 和 arr+1 相差四个字节;
3.&arr+1所加的是整个数组的长度,上方数组 arr 的长度是 20 个字节,所以&arr 和 &arr+1 相差20个字节(地址是以16进制的形式打印的,所以会呈现出这个效果)。
补充:
数组名是首元素的地址,但是有两个例外:
1.遇到sizeof时,计算的是整个数组的大小,单位是字节;
2.&数组名:数组名表示整个数组,取出的是整个数组的地址;
二维数组的数组名:
1.表示的是二维数组首元素的地址;
2.二维数组首元素的地址是第0行的地址。
四.数组指针与指针数组的辨析
例1:
例2:
五.函数指针
是指针,指向的是一个函数
所以说首先得是指针,然后才指向的是函数
具体如下图:
使用方法:
我们来看下面一段代码:
代码语言:javascript
复制
int Add(int x, int y)
{
return x + y;
}
int main()
{
printf("Add=%p\n", Add);
printf("&Add=%p\n", &Add);
return 0;
}
打印结果:
那么这就说明上方的 int (*pf)(int,int)=&Add; 可以写成 ---> int (*pf)(int,int)=Add;
其实这个 * 星号在这里也没什么用,他是为了帮助我们更好的理解,所以上方使用函数指针时还可以写成:int ret=pf(3,5) ; 不管是哪一种写法,最后的结果都是一样的
所以函数名就是函数的地址,即函数名=&函数名
六.两段有趣的代码
1. (* (void ( * )( )0 )();
解析:
2. void ( *singal ( int , void( * ) ( int ) ) ) ( int )
解析:
这样写未免太麻烦,我们可以利用关键字 typedef 来重定义 singal 的返回值类型
如图 :
七.函数指针数组
顾名思义,函数指针数组就是存储函数指针的数组,函数指针指向的函数必须是同一类型的,即函数的参数和返回值相同。
首先得是个数组,然后再存储函数指针。
如图:
函数指针的用途:转移表(出自《C和指针》这本书);
例如我们写一个简易的计算器代码:
代码语言:javascript
复制
void menu()
{
printf("********************************************************\n");
printf("********* 1.Add 2.Sub **********\n");
printf("********* 3.Mul 4.Div **********\n");
printf("********* 0.exit **********\n");
printf("********************************************************\n");
}
int Add(int x, int y)
{
return x + y;
}
int Sub(int x, int y)
{
return x - y;
}
int Mul(int x, int y)
{
return x * y;
}
int Div(int x, int y)
{
return x / y;
}
int main()
{
int input = 0;
int (*parr[5])(int, int) = { NULL,Add,Sub,Mul,Div };//使下标所对应的函数与我们期望的一样
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
int x = 0, y = 0, ret = 0;
if (input >= 1 && input <= 4)
{
printf("请输入两个操作数:>");
scanf("%d %d", &x, &y);
ret = (parr[input])(x, y);
printf("ret=%d\n", ret);
}
else if (input == 0)
{
printf("exit\n");
}
else
{
printf("选择错误,重新选择\n");
}
} while (input);
return 0;
}
如果我们不使用函数指针数组,想要实现建议计算器的程序,就要用到很多重复的代码,如果想要给计算器添加更多的计算功能,那势必又要写上许多重复的代码,是我们的程序变得杂乱,可读性不高。
😼😸本篇文章就到这里啦,如有错误或是建议,欢迎小伙伴们指出。😽😻
🦖🐋谢谢你的阅读🦄🐰