1. 程式人生 > >C語言之複雜指標簡析

C語言之複雜指標簡析

指標陣列和陣列指標

  • 指標陣列:首先它是一個數組,陣列的元素都是指標,陣列佔多少個位元組由陣列本身決定。它是“儲存指標的陣列”的簡稱。
  • 陣列指標:首先它是一個指標,它指向一個數組。在 32 位系統下永遠是佔 4 個位元組,至於它指向的陣列佔多少位元組,不知道。它是“指向陣列的指標”的簡稱。

那麼下邊倆個分別叫做什麼呢?
int *p1[4];
int (*p2)[4];
第一個我們稱之為指標陣列。“[ ]”的優先順序比“”要高。p1 先與“[ ]”結合,構成一個數組的定義,陣列名為 p1,int 修飾的是陣列的內容,即陣列的每個元素。這是一個數組,其包含 4 個指向 int 型別資料的指標,即指標陣列。
我們可以這樣理解:
這裡寫圖片描述


第二個我們稱之為陣列指標。在這裡“()”的優先順序比“ []”高,“*”號和 p2 構成一個指標的定義,指標變數名為 p2,int 修飾的是陣列的內容,即陣列的每個元素。陣列在這裡並沒有名字,是個匿名陣列。那現在我們清楚 p2 是一個指
針,它指向一個包含 4 個 int 型別資料的陣列,即陣列指標。
同樣,也可以這樣理解:
這裡寫圖片描述

函式指標,函式指標陣列和指向函式指標陣列的指標

  1. 函式指標:就是函式的指標。它是一個指標,指向一個函式。
  2. 函式指標陣列:它是一個數組,陣列記憶體儲了指向函式的指標。
  3. 函式指標陣列指標:它是一個指標,只不過這個指標指向一個數組,這個數組裡面存的都是指向函式的指標。

    看如下例子:
    char * (pf)(char p1,char * p2);
    這個我們稱之為函式指標。” * “號和 pf 構成一個指標的定義,指標變數名為 pf。pf指向一個函式,該函式的返回值型別是char * ,函式引數有兩個,分別為p1和p2,p1和p2都是char * 型別.

    char * (pf[3])(char p);
    這個我們稱之為 函式指標陣列。“[ ]”的優先順序比“*”要高。pf 先與“[ ]”結合,構成一個數組的定義,陣列名為 pf。陣列記憶體儲了 3 個指向函式的指標。這些指標指向一些函式,其中函式返回值型別為指向字元的指標,引數為一個指向字元的指標。

    char * ((*pf)[3])(char p);
    這個稱為 指向函式指標陣列的指標。該 pf 確實是實實在在的指標。這個指標指向一個包含了 3 個元素的陣列;這個數組裡面存的是指向函式的指標;這些指標指向一些返回值型別為 指向字元的指標、引數為一個 指向字元的指標 的函式。

下面通過轉移表瞭解一下函式指標陣列的用法:

void menu()
{
    printf("**************************\n");
    printf("*******1.add   2.sub*****\n");
    printf("********3.mul   4.div*****\n");
    printf("****************0.exit*****\n");
    printf("請選擇:");
}
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 = 0;
    int y = 0;
    int input = 1;
    int ret = 0;
    int (*p[5])(int , int ) = { 0, Add, Sub, Mul, Div };//轉移表
    do
    {
        menu();
        scanf("%d", &input);
        if (input >=1 && input <=4)
        {
            printf("輸入運算元:");
            scanf("%d%d", &x, &y);
            ret = p[input](x, y);
        }
        else
        {
            printf("輸入錯誤,請重新輸入:");
        }
        printf("ret=%d\n", ret);

    } while (input);
    system("pause");
    return 0;
}

小試:
(* (void(*) ())0)();
void (* signal(int,void(*)(int)))(int);

第一個為函式呼叫。怎麼理解呢?
首先 void (* )()是一個函式指標,該指標指向一個無引數,返回值型別為void型(即沒有返回值)的函式。
(void (* )())0:就是將0強制轉換成函式指標型別。
(* (void (*)())0):就是取0地址處開始的一段記憶體裡面的內容,其內容就是儲存在首地址為 0 的一段區域內的函式。
(* (void(*) ())0)():就是對函式進行呼叫。

第二個可以理解為:
signal是一個函式,其返回值型別為void (*) (int)型,即函式指標型別;引數有兩個,分別為整形和函式指標型別。可簡寫為:
typedef void (*pfun_t) (int);
pfun_t signal(int , pfun_t);

回撥函式:

就是一個通過函式指標呼叫的函式。如果你把函式的指標(地址)作為引數傳遞給另一個函式,當這個指標被用來呼叫其所指向的函式時,就說這是回撥函式。
使用回撥函式,模擬實現qsort。

int int_cmp(const void* p1, const void* p2)
{
    if (*(int *)p1 > *(int *)p2)
    {
        return 1;
    }
    else if (*(int *)p1 < *(int *)p2)
    {
        return -1;
    }
    else
    {
        return 0;
    }
}
void _swap(void *p1, void *p2, int size)
{
    int i = 0;
    for (i = 0; i < size; i++)
    {
        char tmp = *((char *)p1 + i);
      *((char *)p1 + i) = *((char *)p2 + i);
       *((char *)p2 + i)=tmp;
    }
}
void mybubble(void *base, int count, int size, int(*cmp)(void *, void*))
{
    int i = 0;
    int j = 0;
    for (i = 0; i < count - 1; i++)
    {
        for (j = 0; j < count - i - 1; j++)
        {
            if (cmp((char *)base + j*size, (char *)base + (j + 1)*size)>0)
            {
                _swap((char *)base + j*size, (char *)base + (j + 1)*size, size);
            }
        }
    }

}
int main()
{
    int a[] = { 1, 2, 2, 56, 32, 6, 8, 0 };
    char *arr[] = { "aabb", "dddd", "bbbb", "eeee" };
    int i = 0;
    mybubble(a, sizeof(a) / sizeof(a[0]), sizeof(int), int_cmp);
    for (; i < sizeof(a) / sizeof(a[0]); i++)
    {
        printf("%d ", a[i]);
    }
    printf("\n");
    system("pause");
    return 0;
}

指標概述:
這裡寫圖片描述