指針數(shù)組,數(shù)組指針,函數(shù)指針及應用(回調(diào)函數(shù))

原文地址: https://blog.csdn.net/erica_ou/article/details/80809543

指針數(shù)組與數(shù)組指針

當我們在學習指針與數(shù)組時總會遇到兩個令人容易混淆的概念:數(shù)組指針與指針數(shù)組。
??在這里\color{blue}{數(shù)組指針是指向數(shù)組的指針,其本質為指針指向的對象是數(shù)組。}由于數(shù)組的形式多樣所以數(shù)組指針的表達也十分多樣。同理,\color{blue}{指針數(shù)組就是存放指針的數(shù)組,其本質為數(shù)組。}由于“[ ]”的優(yōu)先級高于“ * ”的優(yōu)先級,指針數(shù)組與數(shù)組指針的表達可做如下表示:

int * p1 [10];??//?指針數(shù)組??p1先與“[ ]”結合構成一個包含10個元素的數(shù)組,int*表示的則是數(shù)組的內(nèi)容。
int (* p2)[10];??//?數(shù)組指針??p2先與“ * ”構成指針定義,int表示數(shù)組內(nèi)容,[10]表示數(shù)組內(nèi)元素個數(shù)。

由于指向數(shù)組的指針與指向普通整型變量的指針不同,在這里可以再對“數(shù)組名”與“&數(shù)組名”的關系進行理解。
??在一維數(shù)組中,數(shù)組名表示指向首元素的首地址,是一個指向普通變量的指針常量,當對其+1時偏移量是一個普通數(shù)據(jù)類型的內(nèi)存大小。而在數(shù)組名前加上取地址符&后,表示的就是一個指向數(shù)組的指針常量對其+1時偏移量是一個數(shù)組的內(nèi)存大小。
??觀察以下代碼:

int main ()
{
    char arr[5] = {'A','B','C','D'};
    char(*p1)[3] = &arr;   //p1指向一個具有三個字符元素的數(shù)組
    char(*p2)[3] = arr;    //p2也指向一個具有三個字符元素的數(shù)組
    printf("arr = %p\n",arr);
    printf("p1 = %p\n",p1);
    printf("p1+1 = %p\n",p1+1);
    printf("p2+1 = %p\n",p2+1);
    return 0;
}

在這段代碼當中,p1,p2都是指向由3個整型元素組成的數(shù)組的指針,但arr卻是一個指向整型數(shù)據(jù)的指針常量,二者的指向內(nèi)容雖然不同但是由于當變量作為右值時編譯器只會去取變量的值,所以在程序運行時編譯器會報出如警告卻不會運行失敗。

e:\code\c語言\test\test.c(16) : warning C4048: “char ()[10]”和“char ()[5]”數(shù)組的下標不同
e:\code\c語言\test\test.c(17) : warning C4047: “初始化”: “char ()[10]”與“char ”的間接級別不同

int main ()
{
    char arr[5] = {'A','B','C','D'};
    char(*p1)[10] = &arr;//p1指向一個具有三個字符元素的數(shù)組,與arr指向空間一致
    char(*p2)[10] = arr;
    printf("arr = %p\n",arr);
    printf("p1 = %p\n",p1);
    printf("p1+1 = %p\n",p1+1);
    printf("p2+1 = %p\n",p2+1);
    return 0;
}

總結代碼可以看出 指向數(shù)組的指針初始化時只是用到了原數(shù)組提供的地址,其訪問的內(nèi)容大小并不受原數(shù)組arr限制,而受到自己指向的數(shù)組大小的影響即:p1+1的偏移量是10而不是原數(shù)組大小(&arr)的4,p2+1的偏移量也是10而不是原指針指向元素的大小(arr首元素大小)的1。

對于數(shù)組指針最重要的是要理解其本質是指針,而且其偏移量受到自身指向的數(shù)組大小影響即可。相較之下,指針數(shù)組就很好理解了,不過是本質是數(shù)組且每個數(shù)組元素是指針罷了(不管是指向何種類型的指針在32位平臺下其自身的空間占用量都是4個字節(jié))。


函數(shù)指針

知道了數(shù)組指針是指向數(shù)組的指針,那么同理也可以對函數(shù)指針進行相同的理解,函數(shù)指針就是指向函數(shù)的指針了。
??函數(shù)在內(nèi)存中占用一塊地址而且這塊地址也是可以賦給一個指針變量的,也就是說可以通過這個地址訪問到這個函數(shù)。與數(shù)組相似,函數(shù)名也是指向函數(shù)第一條指令的常量指針。\color{blue}{所以說函數(shù)的調(diào)用可以通過函數(shù)名,也可以通過指向函數(shù)的指針來調(diào)用。}函數(shù)指針還允許將函數(shù)作為參數(shù)傳遞給其他函數(shù),也就是回調(diào)函數(shù)。
??函數(shù)指針表現(xiàn)形式:\color{red}{type\ (*func)(type\ \&,type\ \&)}該語句聲明了一個指針func,它指向了一個函數(shù),這個函數(shù)帶有了2個type型參數(shù)并返回一個type的值。
??\color{red}{需要特別注意的是第一個括號一定要寫,如果不寫的話表達式就變成了函數(shù)聲明而非函數(shù)指針.}
??分析以下兩句代碼,看看是什么意思:

1.(*(void (*)())0)();
2.void(*signal(int,void(*)(int)))(int);

表達式1:


表達式2:


對于函數(shù)指針暫時只需要明白其表達方法,以及如何利用函數(shù)指針調(diào)用函數(shù)即可。


函數(shù)指針數(shù)組&指向函數(shù)指針數(shù)組的指針
??在對函數(shù)指針有了一定的了解之后,函數(shù)指針數(shù)組就很好理解了,其意義就是定義一個數(shù)組,數(shù)組的內(nèi)容均是指向函數(shù)的指針。
??表達式:

例如:int (*arr1[10])(); 

arr1先于[]結合,表明其本質是數(shù)組,其指向的類型是int (*)()返回值為int的函數(shù)。即函數(shù)指針數(shù)組。
??其應用參考:利用函數(shù)指針數(shù)組實現(xiàn)計算器;

當定義了一個函數(shù)指針數(shù)組后,能否在定義一個指針用于保存這個數(shù)組的地址呢?這個指針就是指向函數(shù)指針數(shù)組的指針。其表達式為:

例如:void (*(*p)[5]) )(void) 

表示 一個指向有5個元素每個元素為指向一個返回值為空的函數(shù)的數(shù)組的指針。


函數(shù)指針實例(回調(diào)函數(shù),實現(xiàn)泛型冒泡排序)

#include<stdio.h>
#include<string.h>
void swap(char *p,char *q, int n)
{
    unsigned int i = 0;
    char tmp;
    for(i=0; i<n; i++)
    {
        tmp = *p;
        *p = *q;
        *q = tmp;
        p++;
        q++;
    }
}
int int_cmp(const void *p,const void *q)//實現(xiàn)整型間的排序
{
    return (*(int *)p > *(int *)q);
}
int char_cmp(const void *p,const void *q)//實現(xiàn)字符間的排序
{
    return (*(char *)p > *(char *)q);
}
int str_cmp(const char **p,const char **q)//實現(xiàn)字符串排序
{
    return strcmp(*p,*q);
}
void bubble(void *arr,int sz,int wid,int(*cmp)(const void *p,const void *q))
{
    unsigned int i = 0;
    unsigned int j = 0;
    for(i=0;i<sz-1;i++)
    {
        for(j=0;j<sz-i-1;j++)
        {
            if(cmp((char *)arr+wid*j ,(char *)arr+wid*(j+1))>0)
            //函數(shù)指針調(diào)用
            {
                swap((char *)arr+wid*j,(char *)arr + wid*(j+1),wid);
            }
        }
    }
}

int main()
{
    int arr[10] = {0,11,33,22,44,55,66,88,77,99};
    int wid = sizeof(arr[0]);
    int sz = sizeof(arr)/sizeof(arr[0]);
    int i = 0;
    bubble(arr,sz,wid,str_cmp);//第四個參數(shù)要根據(jù)排序的不同類型進行更改
    for(i=0;i<sz;i++)
    {
        printf("%s\n",arr[i]);
    }
    printf("\n");
    return 0;
}


函數(shù)指針數(shù)組實例(實現(xiàn)計算器)

#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)
{
    return x/y;
}
void menu()
{
    printf("******************************\n");
    printf("**     1. add     2. sub    **\n");
    printf("**     3. mul     4. div    **\n");
    printf("**          0.exit          **\n");
    printf("******************************\n");
}
void calc(int (*pfun)(int, int))
{
    int x = 0;
    int y = 0;
    int ret = 0;
    printf("請輸入要進行計算的值:");
    scanf("%d%d", &x, &y);
    ret = pfun(x, y);
    printf("ret = %d\n", ret);
}

int main()
{
    int input = 0;
    int x = 0;
    int y = 0;
    int ret = 0;
    int (*pfun[5])(int , int) = {0, Add, Sub, Mul, Div};
    //創(chuàng)建函數(shù)指針的數(shù)組,數(shù)組中保存的都是返回值為int的函數(shù)的指針。
    do
      { 
        menu();
        printf("請選擇:");
        scanf("%d", &input);
        switch(input)
        {
        case 1:
            calc(pfun[1]);
            //通過數(shù)組調(diào)用函數(shù)的指針進而調(diào)用函數(shù),可大量節(jié)省代碼篇幅
            break;
        case 2:
            calc(pfun[2]);
            break;
        case 3:
            calc(pfun[3]);
            break;
        case 4:
            calc(pfun[4]);
            break;
        case 0:
            printf("退出\n");
            break;
        default:
            printf("輸入錯誤,請重新輸入\n");
            break;
        }
    }while(input);
    return 0;
}

本文主要用于學習總結之用,其中主要參考資料有《C語言深度解剖》,《C陷阱與缺陷》,《C和指針》。內(nèi)容中凡有不足疏漏之處歡迎批評指正,謝謝。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 指針是C語言中廣泛使用的一種數(shù)據(jù)類型。 運用指針編程是C語言最主要的風格之一。利用指針變量可以表示各種數(shù)據(jù)結構; ...
    朱森閱讀 3,619評論 3 44
  • C語言是面向過程的,而C++是面向對象的 C和C++的區(qū)別: C是一個結構化語言,它的重點在于算法和數(shù)據(jù)結構。C程...
    小辰帶你看世界閱讀 1,022評論 0 6
  • 前言:復雜類型說明 要了解指針,多多少少會出現(xiàn)一些比較復雜的類型,所以我先介紹一下如何完全理解一個復雜類型,要理解...
    有理想有暴富的小青年閱讀 637評論 0 4
  • 第十章 指針 1. 地址指針的基本概念: 在計算機中,所有的數(shù)據(jù)都是存放在存儲器中的。一般把存儲器中的一個字節(jié)稱為...
    堅持到底v2閱讀 1,170評論 2 3
  • 今天的標題真棒,內(nèi)涵和顏值都有了,實在想不出比標題更好的,所以偷個懶就用這個啦。 身體是革命的本錢,無論要去完成一...
    從容如羊閱讀 189評論 0 5

友情鏈接更多精彩內(nèi)容