一 指针数组

是”指针的数组”,首先这个变量是一个数组,其次,”指针”修饰这个数组,意思是说这个数组的所有元素都是指针类型,在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; 
}