一 指针数组
是”指针的数组”,首先这个变量是一个数组,其次,”指针”修饰这个数组,意思是说这个数组的所有元素都是指针类型,在32位系统中,指针占四个字节。
例如
1 int *arr1[10];
2 char *arr2[4];
分析:第一个定义了一个int * 的数组,数组名为arr1,由于括号优先级高,先与括号优先结合,再与* 结合,所以它是一个数组,而这个数组元素都是int * 的类型。
二 数组指针
数组指针是指向数组地址的指针,其本质为指针;
例如
int (*p)arr[10];
分析: p 先和 * 结合,说明 p 是一个指针变量量,然后指着指向的是一个⼤大⼩小为 10 个整型的数组。所以 p 是 一个指针,指向一个数组,叫数组指针。( 这里要注意: [ ]的优先级要高于 * 号的,所以必须加上()来保证 p 先和 * 结合)。
int arr[10] = {0};
int (*p)[10] = &arr;//p是数组指针,所以存放数组的地址是合适的
三 函数指针
函数指针可以像一般函数一样,用于调用函数、传递参数。在如 C 这样的语言中,通过提供一个简单的选取、执行函数的方法,函数指针可以简化代码。函数指针只能指向具有特定特征的函数。因而所有被同一指针运用的函数必须具有相同的参数和返回类型。
先看一段代码:
#include <stdio.h>
void test()
{
printf("hehe\n");
}
int main()
{
printf("%p\n", test);
printf("%p\n", &test);
}
结果
输出的是两个地址,这两个地址是 test 函数的地址。 那我们的函数的地址要想保存起来,怎么保存? 下⾯面我们看代码:
void test()
{
printf("hehe\n");
}
// 下面 pfun1 和 pfun2 哪个有能力存放 test 函数的地址?
void (*pfun1)();
void *pfun2();
⾸首先,能给存储地址,就要求pfun1或者pfun2是指针,那哪个是指针? 答案是:
pfun1可以存放。pfun1先和*结合,说明pfun1是指针,指针指向的是⼀一个函数,指向的函数 无参数,返回值类型为void。
例如
#include<stdio.h>
int max(int x,int y)
{
return(x>y?x:y);
}
int main()
{
int (*ptr)(int, int);
int a,b,c;
ptr = max;
scanf("%d%d",&a,&b);
c=(*ptr)(a,b);
printf("a=%d,b=%d,max=%d",a,b,c);
}
结果
四 函数指针数组
数组是一个存放相同类型数据的存储空间,那我们已经学习了了指针数组
比如
int *arr[10];
// 数组的每个元素是 int*
那要把函数的地址存到⼀一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义 呢?
int (*parr1[10])(); int *parr2[10](); int (*)() parr3[10];
答案是:parr1 parr1 先和 [ ] 结合,说明parr1是数组,数组的内容是什什么呢?
是 int (*) ( ) 类型的函数指针。
用途: 转移表(计算器)
如果自己写一个计算器,在没学函数指针数组之前我们是这样写的,代码如下:
#include <stdio.h>
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
int Mul(int a, int b)
{
return a*b;
}
int Div(int a, int b)
{
return a / b;
}
int main()
{
int x, y;
int input = 1;
int ret = 0;
while (input)
{
printf( "*************************\n" );
printf( " 1:add 2:sub \n" );
printf( " 3:mul 4:div \n" );
printf( "*************************\n" );
printf( "请选择:" );
scanf( "%d", &input);
switch (input)
{
case 1:
printf( "输⼊入操作数:" );
scanf( "%d %d", &x, &y);
ret = add(x, y);
break;
case 2:
printf( "输⼊入操作数:" );
scanf( "%d %d", &x, &y);
ret = sub(x, y);
break;
case 3:
printf( "输⼊入操作数:" );
scanf( "%d %d", &x, &y);
ret = mul(x, y);
break;
case 4:
printf( "输⼊入操作数:" );
scanf( "%d %d", &x, &y);
ret = div(x, y);
break;
default:
printf( "选择错误\n" );
break;
}
printf( "ret = %d\n", ret);
}
return 0;
}
使用函数指针数组的实现:
#include <stdio.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 Div(int x, int y)
{
if (y == 0)
{
return 'F';
}
else
{
return x / y;
}
}
int main()
{
int a = 0;
int b = 0;
int input = 1;
char ret = 0;
int(*p[5])(int a, int b) = { 0, Add, Sub, Mul, Div };
while (input)
{
printf("**********************************\n");
printf("***** 1.Add 2.Sub *****\n");
printf("***** 3.Mul 4.Div *****\n");
printf("***** 0.Quit *****\n");
printf("**********************************\n");
printf("\n请选择:");
scanf("%d", &input);
if (input >= 1 && input <= 4)
{
begin:
printf("\n请输入操作数:");
scanf("%d %d", &a, &b);
ret = p[input](a, b);
if (ret == 'F')
{
printf("\n输入有误,请重新输入\n");
goto begin;
}
else
{
printf("\nret = %d\n\n", ret);
}
}
else if (input == 0)
{
printf("\n退出\n\n");
}
else
{
printf("\n选择错误\n\n");
}
}
return 0;
}
分析:第一个代码明显有点繁琐,多次使用switch case 语句,而在第二段代码中,定义了一个函数指针数组p 它有五个元素,每个元素是一个函数指针,这些指针存放着其对应函数的地址,简洁明了,避免多次使用switch case 语句。
* 指向函数指针数组的指针*
指向函数指针数组的指针是一个 指针 ,指针指向一个 数组 ,数组的元素都是函数指针 ;
例如:
int * (*(*pf)[5])(int * p);
分析 : 这个指针指向一个包含了5个元素的数组;这个数组里面存的是指向函数的指针;这些指针指向一些返回值类型为指向整形的指针、参数为一个指向整形的指针的函数。
定义如下:
void test(const char* str)
{
printf("%s\n", str);
}
int main()
{
// 函数指针 pfun
void (*pfun)(const char*) = test;
// 函数指针的数组 pfunArr
void (*pfunArr[5])(const char* str);
pfunArr[0] = test;
// 指向函数指针数组 pfunArr 的指针 ppfunArr
void (*(*ppfunArr)[10])(const char*) = &pfunArr;
return 0;
}