関数ポインタとポインタ関数の説明

ポインタ関数

ポインタ関数:
ポインタ関数とも呼ばれ、本質的には関数であり、関数の戻り値としてポインタを返す特殊な関数タイプです。
ポインタ関数宣言の形式:
戻り値の型 * 関数名 (パラメータ リスト);
または < a i =5> 戻り値の型 * 関数名 (パラメータ リスト); このうち、戻り値の型はポインタ型、関数名はポインタ関数の名前、パラメータリストはポインタ関数のパラメータリストです。

推荐使用第一种声明方式。更清晰明了

例:
通常の関数 (つまり、戻り値はアドレスではありません)

int fun0(int);//声明了一个返回值类型为int,函数参数为int型的函数。

ポインタ関数 (つまり、戻り値はアドレス)

int* fun1 (int);//声明了一个返回值为整型的指针,函数参数为int,int的指针型函数。
void* fun2 (int, int);//声明了一个返回值为void型的指针,函数参数为int,int的指针型函数。

注意:ポインター関数には戻り値が必要で、戻り値の型は任意のポインター型である void* の形式になります。値を返さない代わりに。戻り値が int* であるか void* であるかに関係なく、それが null ポインターであるかどうかを判断することをお勧めします。

例:

int* func(int a, int b);//指针型函数声明; 或者为 int* func(int, int);即声明里的形参可以只写类型,不写形参变量。这也是推荐的写法。
	
int* func(int a, int b) //指针型函数的定义
{
   int* p = (int*)malloc(sizeof(int));//在堆内存中申请了一块4个字节的内存,并把指向这块堆内存的地址返回,赋值给指针变量p
   *p = a + b;//将a+b的和,赋值给指针变量p所指向的内存空间。注:当*p作为左值时,表示的就是它所指向的那块内存对应的变量。
   return p;
}

注意:通常の関数と同様に、ポインタ関数に仮引数がない場合、宣言後の括弧()を省略することはできず、省略しないとポインタ変数の定義となります。

ポインタ関数は通常の関数なので、その函数返回值是地址值という理由だけで普通です。この関数と他の一般関数
の唯一の違いは、関数名の前に余分な * 記号があり、この関数がポインタ関数であることです。
一文の要約: 返されるのはアドレス値です。ポインタ関数が呼び出されるとき、ポインタ変数はポインタ関数によって返されたアドレス値を受け取るために使用されます。

関数ポインタ

関数ポインタは関数を指すポインタ変数です。つまり、本質的にはポインタ変数です。したがって、「関数ポインタ」自体はまずポインタ変数である必要があります。
ただし、ポインタ変数は関数を指します。これは、ポインタ変数を使用して整数変数、文字型、配列を指すのと同じで、ここでは関数を指します。 C/C++ がコンパイルされると、各関数にはエントリ アドレスがあり、これは関数ポインタが指すアドレスです。関数を指すポインター変数を取得した後は、ポインター変数を使用して他の種類の変数を参照できるのと同じように、そのポインター変数を使用して関数を呼び出すことができます。これらの概念は一般に一貫しています。関数ポインタには、関数の呼び出しと関数パラメータとしての機能という 2 つの用途があります。

まず int 型ポインターの宣言を確認し、それを関数ポインターと比較します。

int* p;

関数型のポインター (たとえば、int 型の 2 つのパラメーターと int 型の戻り値を持つポインター) を宣言します。

int (*fun_ptr) (int, int);//定义 一个【有两个int类型的参数以及一个int类型的返回值】类型 的函数指针。fun_ptr 就是指针变量名

したがって、このポインタは、一个有两个int类型的参数以及一个 int类型的返回值 に準拠する任意の関数を指すために使用できます。
ここに画像の説明を挿入しますこの 2 つの唯一の違いは、関数ポインタに追加のパラメータ リストがあることです。
例:

#include <iostream>
#include <stdio.h>

void Fun(int a, int b){//函数定义
    std::cout << "a =" << a <<", b=" << b <<std::endl;
};

int Fun1(int a, int b){//函数定义
    std::cout << "a =" << a <<", b=" << b <<std::endl;// a = 2, b = 3
    return 0;
};

int main(int argc, char *argv[])
{

   void (*fun_ptr) (int, int);//定义一个函数指针 

    fun_ptr = Fun;//函数名其实就是函数的地址,函数可以看成和数组名一样都是一个指针常量,即指针的指向地址不可改变
   // fun_ptr = Fun1;//编译报错,函数指针(fun_ptr)的类型 和 Fun1函数的类型不一致。必须要保证返回值和参数列表一样。否则函数指针不能指向此函数地址

    // std::cout << "Fun函数地址:" << Fun <<std::endl;//这样方式打印函数地址会把函数指针转换为bool类型,故打印出来的是总是1,改用下面的printf函数
    fun_ptr(2,3);//使用函数指针来调用函数
    printf("Fun函数的地址为:%p\n",Fun);//Fun函数的地址为:0x400910
    printf("Fun1函数的地址为:%p\n",Fun1);//Fun1函数的地址为:0x400922
    printf("fun_ptr的指向地址:%p\n",fun_ptr);//fun_ptr的指向地址:0x400910
}

関数ポインタの定義とポインタ関数の宣言の違い

関数ポインタの定義

void (*fun) (int, int);//fun 是一个有两个int类型的参数以及一个 int类型的返回值的函数指针。//指针就是变量。变量名是fun.

注意:ポインタとアドレスの違いについて説明しますが、アドレスは定数値であるのに対し、ポインタはアドレスを格納するための変数です。変数とその値の関係に似ています。

ポインタ関数宣言

void* fun (int, int);//fun是返回一个指针的函数

注意:関数ポインタを定義する場合、最初の()は省略できません、省略すると全く別の状況になります。ポインタ関数の宣言になります。

関数ポインタでの typedef の使用

typedef 演算子は C/C++ で頻繁に使用されます。単純な型のエイリアスを作成できるだけではありません。複合型に別名を付けることもできます。
形式は次のとおりです:
typedef 型エイリアス;
C++11 では、次のような使用関数が導入されています。エイリアスを入力します。 using の機能は typedef と同じで同等であり、一部の複雑な型に対して using を使用する方が、typedef を使用するよりも直感的に理解しやすいです。
形式は次のとおりです:
using alias = type;
注意: using の前の機能は、次のような名前空間を導入することです。標準ライブラリ。名前空間: 名前空間 std を使用します。

typedef と alias を使用した関数ポインタの型

関数ポインター型のエイリアスにおける typedef の適用 (これは複合型のエイリアスにおける typedef の適用でもあります):

typedef void (*FUN) (int, int);//这里的FUN是一种 void (*) (int, int) 类型的别名,而不是上面的函数指针,而是一个类型。可以FUN来表示 函数指针 的类型。

注意: typedef void (*) (int, int) FUN; と書くほうが、「typedef type alias;」の形式とより一貫性があるかもしれません。しかし、このように書くとコンパイルエラーが発生するため、この書き方は間違っています。
using を使用してエイリアスを取得することもできます (C++11 でサポートされています)

	using FUN = void (*) (int, int);//感觉这样方式更符合理解。这也是为啥C++11中开始支持使用using来给类型取别名的意义。

注意:typedef または using に関係なく、新しい型を作成するのではなく、既存の単純型または複合型にエイリアスを与えます。

例:

#include <iostream>
#include <stdio.h>

typedef void (*FUNC) (int, int);//使用typedef来取别名
using FUNC1 = void (*) (int, int);//使用using来取别名
using FUNC2 = int (*) (int, int);//使用using来取别名

void Fun(int a, int b){//函数定义
    std::cout << "a =" << a <<", b=" << b <<std::endl;
};

int Fun1(int a, int b){//函数定义
    std::cout << "a =" << a <<", b=" << b <<std::endl;
    return 0;
};

int main(int argc, char *argv[])
{

    FUNC fun_ptr = Fun; //比直接 void (*fun_ptr) (int, int) = Fun;写简洁
    FUNC1 fun_ptr1 = Fun; //比直接 void (*fun_ptr1) (int, int) = Fun;写简洁
    FUNC2 fun_ptr2 = Fun1; //比直接 int (*fun_ptr2) (int, int) = Fun1;写简洁

     // std::cout << "Fun函数地址:" << Fun <<std::endl;//这样方式打印函数地址会把函数指针转换为bool类型,故打印出来的是总是1,改用下面的printf函数
    fun_ptr(2,3);//使用函数指针来调用函数  // a = 2, b = 3
    fun_ptr1(5,3);//使用函数指针来调用函数 // a = 5, b = 3
    fun_ptr2(6,3);//使用函数指针来调用函数 // a = 6, b = 3
    printf("Fun函数的地址为:%p\n",Fun);//Fun函数的地址为:0x400910
    printf("Fun1函数的地址为:%p\n",Fun1);//Fun1函数的地址为:0x400922
    printf("fun_ptr的指向地址:%p\n",fun_ptr);//fun_ptr的指向地址:0x400910
    printf("fun_ptr1的指向地址:%p\n",fun_ptr1);//fun_ptr1的指向地址:0x400910
    printf("fun_ptr2的指向地址:%p\n",fun_ptr2);//fun_ptr2的指向地址:0x400922
    return 0;
}

typedef と関数の型の別名を使用します

関数型にエイリアスを与えることもできます

typedef void FUNC4(int, int);//使用typedef来给函数的类型取别名,不看 前面的typedef 单独看 void FUNC4(int, int);是一个函数声明,即函数原型。

関数ポインターの別名と比較します。

typedef void (*FUNC) (int, int);//使用typedef来给函数指针的类型取别名
分析:
//void (*FUNC) (int, int); //定义一个 返回值为void,拥有两个int参数类型的 函数指针,函数指针名称为FUNC
//void FUNC4(int, int); //声明一个 返回值为void,拥有两个int参数类型的 函数,此函数的函数名是 FUNC4.
//它们就是一个表示 函数指针,一个表示函数
//同理 形如上面的 两者前面都加上typedef后,FUNC表示的函数指针的类型别名。 FUNC4表示的函数的类型的别名。

完全なコードデモ:

#include <iostream>
#include <stdio.h>

typedef void (*FUNC) (int, int);//使用typedef来给函数指针的类型取别名
typedef void FUNC4(int, int);//使用typedef来给函数的类型取别名,不看 前面的typedef 单独看 void FUNC4(int, int);是一个函数声明,即函数原型。
//或者使用using
//using FUNC = void (*) (int,int); //等号右侧表示函数指针的类型
//using FUNC4 = void (int,int); //等号右侧表示函数的类型
//两个类型的区别就是一个有*,一个没有*


//void (*FUNC) (int, int); //定义一个 返回值为void,拥有两个int参数类型的 函数指针,函数指针名称为FUNC
//void FUNC4(int, int); //声明一个 返回值为void,拥有两个int参数类型的 函数,此函数的函数名是 FUNC4.
//它们就是一个表示 函数指针,一个表示函数
//同理 两者前面都加上typedef后,FUNC表示的函数指针的类型别名。 FUNC4表示的函数类型的别名。

void Fun(int a, int b){//函数定义
    std::cout << "a =" << a <<", b=" << b <<std::endl;
};

int Fun1(int a, int b){//函数定义
    std::cout << "a =" << a <<", b=" << b <<std::endl;
    return 0;
};

int main(int argc, char *argv[])
{
    FUNC fun_ptr = Fun; //比直接 void (*fun_ptr) (int, int) = Fun;简洁
    FUNC4* fun_ptr3 = Fun;// 在FUNC4后加* 表示的就是函数指针的类型。可以这样理解 FUNC4是函数的类型 FUNC4*就是指向 和FUNC4相同类型的函数地址 的指针的类型。
    //(void (int,int))* fun_ptr3 = Fun; //直接这样写语义会报错,这也就是为啥用typedef来给复杂类型取别名的用处,至于编译解析交给编译器完成。

    // std::cout << "Fun函数地址:" << Fun <<std::endl;//这样方式打印函数地址会把函数指针转换为bool类型,故打印出来的是总是1,改用下面的printf函数
    fun_ptr(2,3);//使用函数指针来调用函数  // a = 2, b = 3
    fun_ptr3(5,3);//使用函数指针来调用函数 // a =5, b=3
    printf("Fun函数的地址为:%p\n",Fun);//Fun函数的地址为:0x400910
    printf("fun_ptr3的指向地址:%p\n",fun_ptr3);//fun_ptr的指向地址:0x400910
    return 0;
}

おすすめ

転載: blog.csdn.net/adminstate/article/details/134749185