这里我们主要对 指针数组 数组指针 函数指针 函数指针的数组和函数指针数组的指针从多方面做个解释:
一:指针数组
指针数组是可以存放不同类型变量地址的数组,如:
int *arr1[10]; char *arr2[10]; char **arr3[10]; 都是合法的定义
int *arr1[10] arr1 先和 [] 结合,说明 arr1 是一个数组,有能力存储 10 个整形变量的地址
注:[] 的优先级高于 * 的优先级
二:数组指针
数组指针是有能力指向一个数组的指针,如:
int (*p)[10] p 先和 * 结合,说明 p 是一个指针,指向的是一个大小为 10 的整形数组。所以 p 是一个指针,指向的是一个数组,叫指针数组
数组指针的使用
int arr[10] = {0};
arr: //表示数组首元素的地址
&arr; //表示数组的地址
printf("%p\n",arr+1);
printf("%p\n",&arr+1);
我们可以看到结果是完全不同的,这是因为数组地址和数组首元素的地址值是相同的,但意义是不同的。我们都知道对指针加一表示加上其指向类型的大小(单位是字节),
所 以 arr+1 指向下一个元素,&arr+1 指向下一个数组
数组指针的存储
int arr[10] = {0}; //&arr 是数组指针
int *p1 = &arr; //左值是一个整形指针,左右两侧类型不一致
int (*p2)[5] = &arr; //左值是一个整形数组指针,左右两侧类型一致,所以 p2 是相对比较合适的选择
指针和数组的定义 声明(举个例子说明)
//test.c
char arr[] = "abcdef"; //数组的定义
char *p = "abcde"; //指针的定义
//main.c
extern char arr[]; //数组的申明
extern char *p; //指针的申明
int main()
{
printf("%s\n",arr);
printf("%s\n",p);
return 0;
}
在 main.c 中的 extern 表示arr 和 p 是外部文件定义的变量,在使用的时候去其他模块查找
注:申明和定义时避免出现申明和定义不一致的情况
数组参数 指针参数(这里重点解释当数组和指针作为参数传递时形参该如何设计的问题)
数组作为参数传参时会发生降级,不管是几维数组都会降级成指向其内部元素类型的指针,形参的设计理解这一点就能解决
一维数组传参
#include<stdio.h> void test(int arr[]) {} //void test(int arr[10]) //{} //void test(int *arr) //{} void test2(int *arr[20]) {} //void test2(int **arr) //{} int main() { int arr[10] = {0}; int *arr2[20] = {0}; test(arr); test2(arr2); return 0; }
根据我们上面的原则,这里五个形参的设计都是正确的
二维数组传参
void test(int arr[3][5]) //ok
{}
//void test(int arr[][5]) //ok
//{}
//void test(int arr[][]) //error
//{}
//二维数组传参只能不写第一个 [] 的数字。其实该数字在形参中是无法访问的,该数字通常借助另一个参数传入
//根据数组作为形参传递的原则,二维数组传参时降级成指向一维数组的指针 //void test(int *arr) //error
//{}
//void test(int *arr[5]) //error
//{}
//void test(int (*arr)[5]) //ok
//{}
//void test(int **arr) //error
//{}
int main()
{
int arr[][35] = {0};
test(arr);
}
当指针作为函数参数传递时只要实参和形参的类型和指针级别一致就行
三:函数指针
首先看一段代码
#include<stdio.h>
void test()
{
;
}
int main()
{
printf("%p\n",test);
printf("%p\n",&test);
return 0;
}
输出的结果是一样的,都表示 test 函数的地址,函数名(代码)只有只读属性,这里将 test 和 &test 高度统一,二者都表示的是函数的地址;我们知道数组指针的值和第
一个元素指针的值是一样的,同样可将函数的地址理解成第一条指令的地址。
函数指针要用指针来存储,如:
void (*pfun)(); pfun 先和 * 结合,说明 pfun 是一个指针,指向的是一个函数,指向的函数无参数,返回值类型为 void
四:函数指针数组
数组是一个存储相同类型数据的空间,把函数的地址存放到一个数组中,这个数组就叫函数指针数,如:
int (*parr[10])(); parr 先和 [] 结合,说明 parr 是一个数组,存储的内容是 int (*)() 类型的函数指针
五:函数指针数组的指针
函数指针数组的指针是一个指针,指针指向一个数组,数组的内容是函数指针,如:
void ((*pfun)[10])();