【本次任务】
- 指针数组
- 数组指针
- 函数指针
- 函数指针数组
- 指向函数指针数组的指针
【指针数组】
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;
}
上期回顾:
指针(上)