【本次任务】
- 指针数组
- 数组指针
- 函数指针
- 函数指针数组
- 指向函数指针数组的指针
【指针数组】
1.指针数组就是数组,是存放指针(地址)的数组。
2.正确定义指针数组:int *P[10]; //p是一个指针数组,里面存放10个整形元素的地址
3. char **p[10]; //定义一个二级字符指针数组
4.定义一个指针数组求元素个数:
char *arr[] = { "vvv", "ssss", "aaa", "cccc", "dddd", "sss" };
int num = sizeof(arr) / sizeof(arr[0]);
5.输出指针数组元素:
int i = 0;
for (i = 0; i < num; i++)
{
printf("%s ", arr[i]);
}
【数组指针】
1.数组指针是指针,指向数组的地址。
2.正确定义一个数组指针:int (*p)[10]; //指针p指向一个大小为10的整形数组
int (*a[5])[10] //a是整形数组指针数组
int (*(*a)[5])[10] //a是数组指针的数组指针
3.指针数组和数组指针书写:根据优先级判断是前者还是后者。[ ]的优先级高于*,所以指针数组中p先与数组[]结合在于指针结合,所以称为指针数组。同理,由于数组指针加了圆括号所以变成数组指针。
4.数组指针应用:
int main() { int a[10] = { 0 }; printf("%p\n", a); printf("%p\n", &a); printf("%p\n", a + 1); printf("%p\n", &a + 1); //上述打印值中a和&a一样,但其本质不一样,a表示数组首元素地址,而&a表示整个数组的地址, //所以a+1表示数组第二个元素的地址,&a+1表示下一个数组的地址(跨越了整个数组) int arr[10] = { 1,2,4,0 }; int(*p)[10] = &arr; //数组指针 printf("%d\n", **p); //1 printf("%d\n",*(*p+2)); //4 printf("%d\n", (*p)[2]); //4 system("pause"); return 0; }在上例子中,&arr是整个数组的地址,所以需要需要数组指针变量p来保存该地址。即
int(*p)[10] = &arr;
要获取数组中的元素:因为保存在了一个数组指针变量中(还是指针),所以需要解引用两次才可以拿到数组元素(**p)。
要获取后面的元素:解引用一次*p表示获取了首元素地址所以*(*p + 2)即可得到元素4;
注:1.数组指针中*(*p+2) = (*p)[2];
2.一级指针中p[2] = *(p+2);
3. 在上例子中定义一个数组指针int (*p)[10]其中10不可以改为其他数字,更不可以不写,因为数组大小也是判定数组类型相同的一个指标,比如在数组传参时第二个维数不可以省略一样。
4.二维数组传参:
int arr[2][5] = {0};
print(arr);
void print(int arr[][5]); //正确,其中第一个维数可以忽略,随便写啥都可以,也可以不写,因为数组传参只需要传类型,不需要传元素的个数,但第二个以后的维数必须要传,因为他们也是判断数组类型的一个指标。如下图警告
void print(int (*arr)[5]); //数组传参会发生降级,将为指向数组其内部元素类型的指针,所以可以用数组指针
数组传参为什么会发生降级?why
因为C语言中函数传参时肯定会形成临时变量, 数组也是一种类型,所以也会形成数组的临时变量,但是给数组整体开辟空间开销会非常大,而且有的数据也用不到,所以,为了减小开销,会发生降级,但数组发生降级,他还会形成临时变量(指针类型的变量)。指针也是一种类型,也会形成临时变量。
例:函数中参数类型为int **arr;可以接收什么类型变量?
第一:int **a ;第二:指针数组(降维)
例:当一个函数参数部分为char *p可以接收什么类型变量?
第一:char *p ;第二:字符串 ;第三:char arr[];
【函数指针】
通过上面的学习,我们应该也对函数指针有了初步的了解。
1.函数指针即函数的地址;保存在函数指针变量里面。
2.定义一个函数指针变量:int (*p)( );
3.函数的地址:函数名或者&函数名代表函数的地址。
void test() { printf("come on!\n"); } int main() { int(*p)() = (int (*)())test; //强转为int (*)()类型 void(*pp)() = test;//不需要强转 printf("%p\n", *p); printf("%p\n", *pp); printf("%p\n", test); printf("%p\n", &test); return 0; }上述四个地址输出一样(函数的地址);
【函数指针数组】
1.函数指针数组即把函数的地址保存在数组;
2.定义方式:int (*p[10])( ); //在数组p里面保存10个int (*)( )类型的函数指针;
3.用途(转移表)
#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> #include<stdlib.h> 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 divv(int x, int y) { if (0 == y) printf("输入错误,分母不能为0!\n"); else return x / y; } int main() { int input = 0; int x = 0; int y = 0; int(*arr[5])(x, y) = { 0, add, sub, mul, divv }; do { printf("******************************\n"); printf("****** 1.add 2.sub *****\n"); printf("****** 3.mul 4.divv *****\n"); printf("****** 0.exit *****\n"); printf("******************************\n"); printf("请选择:>>"); scanf("%d", &input); if (input == 0) break; if (input >= 0 && input <= 5) { printf("请输入x和y的值:>>"); scanf("%d%d", &x, &y); int ret = (*arr[input])(x, y); printf("result = %d\n", ret); } else printf("输入错误,请重新输入:>>"); printf("退出操作请按0,继续操作请按任意非1到4键\n"); } while (input); exit(1); system("pause"); return 0; }
待完善。。。。。。(只是说明了函数指针数组怎么用)
【函数指针数组的指针】
1.函数指针数组的指针就是函数指针数组的地址;
2.定义:void (*(*p)[10])( );
void test() { printf("come on!\n"); } int main() { void(*p)() = test; //函数指针初始化为test的地址 void(*arr[10])(); //定义函数指针数组 arr[0] = test; //数组第一个元素为test的地址 void(*(*pp)[10])() = &arr; //把上一个函数指针数组的地址初始化给函数指针数组的指针变量pp system("pause"); return 0; }上期回顾: 指针(上)