Cポインタ&&関数


一、関数ポインタ
名前の通り、関数ポインタは、まずポインタです.関数を指すことができるので、関数ポインタと呼ばれます.配列ポインタクラスと比較できます.
配列ポインタの定義と同様に、関数ポインタの定義は次のとおりです.
関数戻り値タイプ(*変数名)(関数パラメータタイプ)
void(*pfun)(int)/関数ポインタpfunが指す関数のタイプはvoid(int)
次のコードがどういう意味か判断します
(1)、char * (*fun1)(char * p1, char * p2);
(2)、char * *fun2(char * p1, char * p2);
(3)、char * fun3(char * p1, char * p2);
上記のコードは優先度を考慮すれば,容易に判断できる.
解:
(1)、*はまずfun 1と結合するので、fun 1はポインタであり、削除(*fun 1)はfun 1が指すことができるタイプであるため、fun 1は関数ポインタである.指すことができる関数のタイプはchar*(char*p 1,char*p 2)である.したがって、(1)行文は関数ポインタを定義します.
(2)、()の優先度が*より高いのでfun 2は先に()と結合するのでfun 2は関数であり、関数の戻り値タイプはchar**であり、パラメータ数は(char*p 1,char*p 2)であるため、これは関数の宣言である.
(3)、(2)と同様にfun 3は関数であり、この関数の宣言である.
では、関数ポインタは何に使いますか.関数ポインタは、通常のポインタと同様に参照を解くと、指向するオブジェクトにアクセスできます.関数ポインタを参照すると、関数を呼び出すことができます.
#include 

int add(int a,int b)
{
    return a+b;
}

int main()
{
    int(*padd)(int,int)=&add;//      padd  add()
    int ret=0;
    
    //ret=add(2,3);
    ret=(*padd)(2,3);
    
    printf("%d
",ret);          return 0; }

二、関数ポインタ配列
名前の通り、関数ポインタ配列は、まず配列であり、配列要素が関数ポインタであるため、関数ポインタ配列と呼ばれる.
1、関数ポインタ配列の定義
関数ポインタ配列をどのように定義しますか?
まず、一般的な配列とポインタ配列がどのように定義されているかを見てみましょう.
char arr1[3];//文字配列
char *arr2[3];//ポインタ配列
同様に、char(*arr[3])(char*);//関数ポインタ配列
実はよく理解して、[]の優先度は*より高くて、arrは先に〔3〕と結合して、だからarrは1つの配列で、大きさは3です;arr〔3〕を取り除くと、配列要素のタイプであり、char(*)(char*)は関数ポインタのタイプである.したがってarrは関数ポインタ配列のサイズが3である.
2、配列の初期化
通常の配列を初期化するのと同じように、配列の要素だけが関数のアドレスです.
例えば配列要素はint(int,int)クラス関数を指す
int(*pfun[3])(int,int)={fun1,fun2,fun3}; {&fun 1,&fun 2,&fun 3}
3、関数ポインタ配列の応用(簡易計算機の実現)
#include 

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 input=1;
    int x=0,y=0;
    int ret=0;
    int(*p[4])(int,int)={add,sub,mul,div};
    while(input)
    {
        printf("1.add  2.sub  3.mul  4.div  0.exit
");                  scanf("%d",&input);         if(input>0&&input<5)         {             printf("
");             scanf("%d%d",&x,&y);             ret=(*p[intput-1])(x,y);             printf("%d
",ret);         }         else if(input==0)             break;         else             printf(" ,
");             }     return 0; }

上のコードは関数ポインタ配列を用いて計算機を実現し,関数ポインタ配列を用いずにswitch文を用いることもできるが,計算機の機能が複雑であればcase文が大量に用いられ,この場合関数ポインタ配列を用いることでコード冗長性を低減できる.
三、関数ポインタ配列の配列ポインタ
        
名前の通り、関数ポインタ配列の配列ポインタは、まず1つのポインタであり、1つの配列を指すため、配列ポインタと呼ばれ、またこの配列は関数ポインタ配列であるため、このポインタは関数ポインタ配列を指す配列ポインタである.
以下に、単純な関数ポインタ配列を定義する配列ポインタを示します.
        char * (*(*parr)[3])(char * p);
*まずparrと結合するのでparrはポインタであり、削除(*parr)はparrが指すタイプであり、
char*(*[3])(char*p):*はまず〔3〕と結合し、これはポインタ配列であり、parrは配列を指し、[3]を取り除くと配列のタイプであり、char*(*)(char*p)は関数ポインタタイプであるため、parrは関数ポインタ配列を指す配列ポインタである.
1つの関数ポインタ配列に対してアドレスを取るだけで、取り出したアドレスは関数ポインタ配列のポインタを初期化または付与することができる.
四、コールバック関数
1、概念
コールバック関数とは?
コールバック関数は、関数ポインタによって呼び出される関数です.関数のポインタ(アドレス)をパラメータとして別の関数に渡すと、このポインタが指向する関数を呼び出すために使用されると、コールバック関数と言います.
関数ポインタで1つの関数を呼び出すことができる以上、私たちは1つの関数をカプセル化することができて、プラスとマイナスを実現することができて、また乗算を実現することができますか?答えはいいです.(ここでいう不快感は関数内部で判断して実現する)
//    

#include 

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 op(int (*pfun)(int , int))  //    op,              ,
                               //             
{
    return pfun(1,2);
}

int main()
{
    int input=1;
    int x=0,y=0;
    int ret=0;
    int(*p[4])(int,int)={add,sub,mul,div};
    while(input)
    {
        printf("1.add  2.sub  3.mul  4.div  0.exit
");                  scanf("%d",&input);         if(input>0&&input<5)         {             printf("
");             scanf("%d%d",&x,&y);             ret= op(p[input-1]);             printf("%d
",ret);         }         else if(input==0)             break;         else             printf(" ,
");             }     return 0; }

実は上の例はコールバック関数で実現する必要はありません.これは複雑すぎて、しかも役に立たないので、一方的に理解しています.
2、応用
次にコールバック関数の応用を見てみましょう
バブルソート関数を作成すると、文字列をソートしたり、数値をソートしたり、文字をソートしたりできます.
#include 
#include 

int com_int(const void *elem1, const void *elem2 )
{
    return *(int *)elem1 - *(int *)elem2;
}

int com_str(const void *elem1, const void *elem2)
{
    return strcmp((char *)*(int *)elem1, (char *)*(int *)elem2);
}

int com_char(const void *elem1, const void *elem2)
{
    return*(char*)elem1 - *(char*)elem2;
}

void Swap(char *p1, char *p2, size_t sz)
{
    size_t i = 0;
    for(i = 0; i 0)
	    {
                Swap((char *)base+ width*j, (char *)base+width*(j+1), width);
	    }
	}
    }
}

int main()
{
    //char *arr1[] = {"bbbb","aaaa","dddd","cccc"};
    //int arr1[] = { 1, 3, 5, 7, 2, 4, 6, 8 };
    char arr1[] = "asdggt";
    int i = 0,len=0;
    
    len = sizeof(arr1) / sizeof(arr1[0]);
    
    bubble_sort(arr1,len , sizeof(char), com_char);
    
    for(i = 0 ;i