目录
文章目录
前言
一、字符指针
二、数组指针
三、函数指针
四、函数指针数组
五、函数指针数组指针
六、回调函数
总结
指针的主题,我们在上一篇已经接触过了,我们知道了指针的概念:
1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。3. 指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。4. 指针的运算。
这一篇,我们继续探讨指针的高级主题。
在指针的类型中我们知道有一种指针类型为字符指针 char* 。
一般使用:
int main()
{
char ch = 'w';
char *pc = &ch;
*pc = 'w';
return 0;
}
还有一种使用方式如下:
int main()
{
const char* pstr = "hello world";
printf("%s\n", pstr);
return 0;
}
代码 const char* pstr = "hello world";特别容易让我们以为是把字符串 hello world放到字符指针 pstr 里了,但是本质是把字符串 hello world. 首字符的地址放到了pstr中。
数组指针是指向数组类型数据的指针变量。在C语言中,数组名可以作为指向数组首元素的指针常量,因此数组指针可以直接指向数组。例如:
int arr[5] = {1, 2, 3, 4, 5};
int (*ptr)[5] = &arr;
上面的代码中,ptr
就是一个指向整型数组arr
的指针,(*ptr)[5]
表示一个含有5个元素的整型数组。&arr
表示整个数组的地址,因此ptr
指向了整个数组。
数组指针也可以通过指针运算来访问数组中的元素,例如:
int arr[5] = {1, 2, 3, 4, 5};
int (*ptr)[5] = &arr;
printf("%d\n", (*ptr)[1]);
上面的代码中,(*ptr)[1]
表示指针ptr
所指向的整型数组中的第二个元素,即整数2。
如果数组名已经作为指针使用,可以直接将它赋值给一个数组指针,例如:
int arr[5] = {1, 2, 3, 4, 5};
int *p = arr;
int (*ptr)[5] = (int (*)[5])p;
上面的代码中,将指向整型的指针p
赋值给一个指向含有5个元素的整型数组的指针ptr
,需要将指针类型进行强制转换。
函数指针是指向函数的指针。在C语言中,函数名也可以被看作是一个地址,指向函数的入口点。因此,可以定义一个指向特定函数的指针,以便在代码中动态地引用该函数。
函数指针的语法格式为:
返回类型 (*指针变量名)(参数列表)
其中,返回类型
表示函数返回值的数据类型,参数列表
表示函数的参数类型和顺序,用逗号分隔。例如:
#include
int add(int a, int b)
{
return a + b;
}
int main()
{
int (*pFunc)(int, int) = add; // 声明并初始化一个指向函数add的指针变量pFunc
int result = pFunc(1, 2); // 调用add函数,结果为3
return 0;
}
在上面的示例中,声明并初始化了一个指向add
函数的指针变量pFunc
,并通过指针变量调用了add
函数,并将结果保存到变量result
中。
函数指针还可以用于实现函数回调机制,即将函数指针作为参数传递给其他函数,让被调用函数可以调用传递进来的函数指针,从而实现回调功能。
函数指针数组是一个数组,其中每个元素都是一个函数指针。函数指针数组可以用于存储多个函数指针,以便在程序中动态地引用这些函数。
函数指针数组的语法格式为:
返回类型 (*指针数组名[数组长度])(参数列表)
其中,返回类型
表示函数返回值的数据类型,参数列表
表示函数的参数类型和顺序,用逗号分隔。例如:
#include
int add(int a, int b)
{
return a + b;
}
int sub(int a, int b)
{
return a - b;
}
int main()
{
int (*pFuncArr[2])(int, int) = { add, sub }; // 声明并初始化一个函数指针数组,包含指向add和sub函数的指针
int result1 = pFuncArr[0](1, 2); // 调用add函数,结果为3
int result2 = pFuncArr[1](1, 2); // 调用sub函数,结果为-1
return 0;
}
在上面的示例中,声明并初始化了一个包含2个元素的函数指针数组pFuncArr
,其中第一个元素指向函数add
,第二个元素指向函数sub
。然后使用函数指针数组分别调用了这两个函数,并将结果保存到变量result1
和result2
中。
函数指针数组也可以用于实现函数回调机制,即将函数指针数组作为参数传递给其他函数,让被调用函数可以根据需要调用指定的函数指针,从而实现回调功能。
函数指针数组指针是指一个指向数组,这个数组中的每个元素都是函数指针的指针。这个数组的每个元素都指向一个函数,它们具有相同的参数类型和返回类型。
下面是一个函数指针数组指针的例子:
#include
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int main()
{
int (*funcPtrArr[3])(int, int) = { add, subtract, multiply };
int (*(*funcPtrArrPtr)[3])(int, int) = &funcPtrArr;
printf("%d\n", (*funcPtrArr[0])(1, 2)); // 输出 3
printf("%d\n", (*funcPtrArr[1])(3, 1)); // 输出 2
printf("%d\n", (*(*funcPtrArrPtr)[2])(2, 3)); // 输出 6
return 0;
}
在上面的例子中,我们定义了一个包含3个函数指针的函数指针数组funcPtrArr
,每个指针指向一个具有两个int
类型参数和返回值的函数。然后我们定义了一个指向funcPtrArr
的指针funcPtrArrPtr
,并初始化它。最后,我们通过使用指针解引用操作符*
来访问和调用函数指针。
注意,我们使用funcPtrArr[0]
来访问数组的第一个元素,而使用(*funcPtrArrPtr)[2]
来访问数组的第三个元素。这是因为,当我们想要访问函数指针数组指针中数组元素的时候,需要先解引用指向数组的指针,然后再用索引访问数组元素。
回调函数就是一个被作为参数传递的函数。回调函数也可以说是一种机制,即当一个函数被调用时,它将另一个函数作为参数传递给它,并且在执行过程中调用或“回调”该函数。回调函数可以让我们编写可重用代码,因为该代码可以由其他用户编写的代码通过回调函数来调用。回调函数常用于事件驱动的程序设计中。
下面是一个简单的示例,演示如何使用回调函数:
#include
void ForEach(int arr[], int size, void (*callback)(int))
{
for (int i = 0; i < size; i++) {
callback(arr[i]);
}
}
void Print(int n)
{
printf("%d ", n);
}
int main()
{
int arr[] = { 1, 2, 3, 4, 5 };
int size = sizeof(arr) / sizeof(arr[0]);
ForEach(arr, size, Print); // 将Print函数作为参数传递给ForEach函数
return 0;
}
在上述示例中,定义了一个名为ForEach
的函数,它接受一个整数数组、数组大小和一个指向回调函数的指针作为参数。该函数遍历整个数组,并在处理每个元素时调用回调函数。另外,还定义了一个名为Print
的回调函数,它只是简单地打印它的参数。
在main
函数中,定义一个名为arr
的整数数组并初始化,然后根据数组大小调用ForEach
函数,并将Print
作为回调函数的参数传递。ForEach函数遍历整个数组,并依次调用回调函数Print,输出每个元素的值。
回调函数使程序设计更加灵活和可扩展,通过使用回调函数,我们可以使程序模块化和复用程度提高,同时增加程序的可读性和可维护性。
本文是对指针的深入介绍,主要让我们对指针有进一步的了解。