1. 程式人生 > >指標函式 AND 函式指標 AND 函式指標陣列 AND 指向函式指標陣列的指標

指標函式 AND 函式指標 AND 函式指標陣列 AND 指向函式指標陣列的指標

指標函式

  • 形如“指標陣列”,“指標函式”是一個“函式”,函式的返回型別是指標。
定義
    型別識別符號 *函式名(引數表)
char *reverse(char *left, char *right);

reverse是一個函式,它的返回型別是一個字元型的指標,函式的返回值必須在主呼叫函式中用一個相同型別的的指標變數來接收。

char *my_strcpy(char *dst, const char *src)
{
    char *ret = dst;
    assert(dst);
    assert(src);

    while
(*dst++ = *src++) { ; } return ret; } int main() { char arr1[] = "abcdef"; char arr2[20] = { 0 }; char *ret = my_strcpy(arr2, arr1); printf("%s\n", ret); system("pause"); return 0; }

這個例子使用的是strcpy的模擬實現,此處my_strcpy就是一個指標函式,本質是一個函式,返回值是一個字元型指標,在主函式中使用同類型的字元型指標接收。


函式指標

  • 形如“陣列指標”,“函式指標”是一個“指標”,指向了函式的入口;
先看一段程式碼:
#include <stdio.h>
#include <stdlib.h>

void test(void)
{
    printf("i love you\n\n")int main()
{
test();
printf("test = %p\n", test);
printf("&test = %p\n", &test);

system("pause");
return 0;
}

(函式名)和(&函式名)都輸出了函式的地址



函式的地址如何存放呢?
我們不禁想到了“陣列”的地址是通過“陣列指標”來存放的,那函式的地址是否可以通過“函式指標”來存放呢?還是可以通過“指標函式”來存放?

void (*ptest1)();
void *ptest2();

首先,能儲存地址的必須是一個指標變數,分析可知,ptest1先和*結合,形成指標,指向一個函式,指向的函式無引數,返回值型別為void。

定義
    型別識別符號 (*指標變數名)(引數表)

舉例:大家來說說一下幾個式子分別代表什麼含義?

1.char* fun1(char* p1, char* p2);
2.char* *fun2(char* p1, char* p2);
3.char* (*fun3)(char* p1, char* p2);

1. 是指標函式,fun1是函式名,p1、p2是引數,其型別都為char *,函式的返回值型別是char*,是一個一級指標
2.是指標函式,同1,只不過函式的返回型別為char **,是一個二級指標。 fun2是函式名,p1、p2是引數,其型別都為char *,函式返回值型別是char **,是一個二級指標
3.是函式指標,fun3是指標變數名,指向了一個函式,這個函式有兩個引數為p1、p2,其型別都是char *,函式的返回值型別是char *,如果看不懂可以把式子改寫為:char* (*)(char* p1,char* p2) fun3

看了這些後,我們看兩個程式碼吧!簡述一下它們代表了什麼含義?

1.(*(void(*)())0)();
答:分析步驟如下:
-首先這個式子看一下沒有變數只有常量0,所以我們的突破口就是這裡。
① void(*)() 是一個函式指標,沒有引數沒有返回值。
② (void(*)())0 是將0強轉為函式指標型別,0存放的是一個地址,所以,一個函式存在首地址為0的一段區域內。
③ (*(void(*)())0) 取0地址開始處的一段內村裡面存放的內容,內容就是儲存在首地址為0處的一段區域內的函式。
④ (*(void(*)())0)() 是函式呼叫,呼叫了0地指出的函式,此函式沒有引數。

總結:(*Func)()為呼叫Func指向函式的方式
看了上述總結,是不是有一點懂了?那再看一個同類型的吧!

(*(char** (*)(char**, char**))0)(char**, char**);
答:這裡很容易的就知道啦,此時表達的是,呼叫0地址處的函式,此函式
有2個引數,型別都為char**,有返回值,是char**型別的。
2.void (*signal(int, void(*)(int)))(int);
答:從難到簡的方式我們先看:
① void(*)(int) 我們會知道這個式子的應該是void(*handle(int),無返回值。
② void (*signal(int, void(*)(int)))(int) 可以寫為void(*)() signal(int, void(*)(int)),void(*)(int)是返回型別signal(int, void(*)(int))是一個函式,所以,此式子表達的是一個返回指向返回void值的函式的指標的函式。
③void (*signal(int, void(*)(int)))(int) 是一個函式的宣告,是一個返回指向返回void值的函式的指標的函式的宣告。
可以簡化為:
typedef void(*pfun_t)(int);
pfun_t signal(int pfun_t);

函式指標陣列

大家都知道“陣列”是存放相同型別資料的儲存空間,“函式指標”是一個指向函式的“指標”,那我們就可以知道,“函式指標陣列”是一個存放指向函式的指標的陣列,也可以說為是一個存放函式地址的陣列。

定義

例如:int (*parr1[10])()
首先parr1先和[]結合,說明parr1是一個數組,那麼陣列的內容就是int (*)()型別的函式指標
簡述一下下列的程式碼分別表示什麼意思?

1.char* (*pf1[3])(char* p);
2.int *pf2[3]();
3.int (*)() pf3[3]

1.這是定義一個函式指標陣列。它是一個數組,陣列名為 pf1,陣列記憶體儲了 3 個指向函式的指標。
2.這種寫法屬於錯誤寫法,它什麼都不能表示。
3.這個是定義了一個函式指標陣列。它是一個數組,數組裡面有3個元素,每個元素的型別是int(*)()型別的,所以,這個也是一個函式指標陣列,可以寫為int(*pf3[3])()。

函式指標陣列的應用

我們通過函式指標陣列存放每個演算法函式的地址,不就可以找到每個元素函數了嗎?
這裡寫圖片描述

void menu(void)
{
    printf("**************************\n");
    printf("**   1.add      2.sub   **\n");
    printf("**   3.mul      4.div   **\n");
    printf("**   0.exit             **\n");
    printf("**************************\n");
}

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 dive(int x, int y)  //除法
{
    return x / y;
}
void test(void)
{
    int input = 0;
    int x = 0, y = 0;
    int ret = 0;
    int(*p[5])(int x, int y) = { 0, add, sub, mul, dive };  //函式指標陣列,存放了各個函式的地址
    do
    {
        menu();
        printf("請選擇:>");
        scanf("%d", &input);
        if ((input > 0 && input < 5))
        {
            printf("請輸入運算元(x y):>");
            scanf("%d%d", &x, &y);
            ret = (*p[input])(x, y);
            printf("ret = %d\n", ret);
        }
        else if (input == 0)
        {
            return;
        }
        else
        {
            printf("輸入有誤\n");
        }
    } while (input);
}
int main()
{
    test();
    system("pause");
    return 0;
}

這裡寫圖片描述


指向函式指標陣列的指標

首先指向函式指標陣列的指標應該是一個指標,那麼,指標指向一個數組,陣列元素都是函式指標;

void (*(*pp)[10])(const int *);

它表示的是一個指向函式指標陣列的指標,這個指標指向的陣列有10個元素,每個元素都是函式指標,指向的函式無返回值,有一個引數,是不可修改的整型指標。


小總結

1.函式指標是指標,它存放的是函式的地址
2.函式指標陣列是陣列,它的元素型別都是函式指標
3.指向函式指標陣列的指標是指標,它存放的是函式指標陣列的地址