引言

        在C语言中,指针是一种非常强大且灵活的工具,它可以让我们直接操作内存,处理数据。然而,指针的理解和使用也是C语言学习中的难点。

        本文将深入探讨五种不同的指针类型:指针数组、数组指针、函数指针、函数指针的数组以及指向函数指针数组的指针。通过理解这些指针类型,你可以更深入地理解C语言的底层原理,提高编程效率,为日后的编程工作打下坚实的基础。

一、指针数组

1.概念

        指针数组是一个数组,其元素类型为指针。

2.作用

        在C语言中,指针数组常用于存储和管理多个指针变量。指针数组可以有一维、多维等形式。(本文主要讲解一维指针数组)

3.应用场景

指针数组的应用场景主要有以下几点:
        1. 存储和管理多个指针变量:当我们需要处理多个指针变量时,可以使用指针数组来存储和管理这些指针变量。例如,一个程序可能需要处理多个文件,每个文件都有一个文件指针,我们可以使用一个指针数组来存储这些文件指针。
        2. 用于函数指针数组:函数指针数组是一个包含多个函数指针的数组。每个函数指针都指向一个函数,通过索引访问函数指针数组,可以调用相应的函数。例如,我们可以定义一个函数指针数组,用于存储多个排序算法的函数指针,然后根据需要调用相应的排序函数。
        3. 用于多维数组的行指针或列指针:在处理多维数组时,我们可以使用指针数组来存储每一行或每一列的指针。这样,我们可以通过指针数组的索引来访问多维数组的任意一行或一列。例如,对于一个二维数组,我们可以使用一个指针数组来存储每一行的指针,然后通过索引访问对应的行。
        4. 用于实现字符串数组:在C语言中,字符串是以字符数组的形式存储的,而字符数组的元素类型是字符型指针。因此,我们可以使用指针数组来存储多个字符串,每个字符串的长度可以不同。通过访问指针数组,我们可以获取每个字符串的长度和内容。

4.示例

//数组指针——数组中有10个元素,每个元素都是指针
int *ptrArray[10];

(使用C语言详解)指针数组、数组指针、函数指针、函数指针的数组、指向函数指针数组的指针_函数指针

上述代码定义了一个一维指针数组,数组的名称为ptrArray。该数组包含10个元素,每个元素都是指向int类型的指针。

5.应用实验代码举例

以下是是一个使用指针数组的简单项目示例,该项目创建了一个NBA球员信息数组,并使用指针数组来存储每个球员的姓名和得分。

#include <stdio.h>

int main() {
    // 定义球员信息结构体
    struct Players {
        char name[50];
        int points;
    };

    // 定义球员数组
    struct Players players[3] = {
        {"Curry", 37},
        {"Klay", 24},
        {"Wiggins", 14}
    };

    // 定义指针数组
    char* namePtrArray[3] = { players[0].name, players[1].name, players[2].name };
    int* pointsPtrArray[3] = { &players[0].points, &players[1].points, &players[2].points };

    // 使用指针数组访问球员信息
    for (int i = 0; i < 3; i++) {
        printf("name:%s, points:%d\n", namePtrArray[i], *pointsPtrArray[i]);
    }

    return 0;
}

(使用C语言详解)指针数组、数组指针、函数指针、函数指针的数组、指向函数指针数组的指针_数组_02

二、数组指针

1.概念

        数组指针:是一种特殊的指针,它指向数组的首元素。

2.作用

        数组指针可以用来存储数组的地址,并通过指针进行索引来访问数组中的元素。在C语言中,数组指针常用于处理多维数组。

3.应用场景

        1. 处理多维数组:数组指针常用于处理多维数组,例如二维数组、三维数组等。通过数组指针,可以简化数组元素的访问,提高代码的可读性和可维护性。
        2. 数组排序:数组指针可以用于数组排序,例如冒泡排序、快速排序等。通过使用数组指针,可以避免在排序过程中对数组元素进行多次解引用操作,提高排序算法的效率。
        3. 数组查找:数组指针可以用于数组查找,例如二分查找等。通过使用数组指针,可以快速定位数组中的目标元素,提高查找算法的效率。
        4. 数组切片:数组指针可以用于数组切片,例如取出数组中的某一部分元素构成一个新的数组。通过使用数组指针,可以避免对原数组进行多次复制操作,提高代码的效率。
        5. 数组拼接:数组指针可以用于数组拼接,例如将两个数组首尾相连构成一个新的数组。通过使用数组指针,可以避免对原数组进行多次复制操作,提高代码的效率。

4.示例

//数组指针-pa指向的数组是10个元素
int* (*pa)[10] = &arr;

(使用C语言详解)指针数组、数组指针、函数指针、函数指针的数组、指向函数指针数组的指针_函数指针数组_03

以上代码定义了一个指向指针的指针pa,pa指向一个包含10个整型指针的数组。

(*pa)是一个指针,指向的是包含10个元素的数组Arr。

(*pa)指向Arr的类型是int*,因为数组Arr[10]的数据类型为int*。

三、函数指针

1.概念

        函数指针是C语言中的一种特殊类型的指针,它指向函数。

2.作用

        函数指针可以存储函数的地址,通过函数指针可以调用函数。

3.应用场景

        1. 函数表:函数指针可以用于实现函数表,函数表是一种存储多个函数地址的数据结构。通过函数表可以实现对多个函数的调用。这在需要根据不同的条件或参数来选择不同的函数时非常有用。
        2. 回调函数:函数指针可以用于实现回调函数,回调函数是一种在某个时间点自动调用的函数。通过函数指针可以实现定时调用函数,这在需要周期性执行某个任务时非常有用。
        3. 传递函数:函数指针可以用于将函数作为参数传递给其他函数。这在需要根据不同的条件或参数来选择不同的函数时非常有用。
        4. 函数指针数组:函数指针可以用于创建函数指针数组,这样可以在数组中存储多个函数指针。这在需要根据不同的条件或参数来选择不同的函数时非常有用。
 

4.示例

int Add(int x, int y) {
	return x + y;
}

int main() {
	//函数指针
    //pAdd存放函数地址的指针
	int(*pAdd)(int, int) = Add;
	int sum = (*pAdd)(11, 30);
	printf("sum =%d\n", sum); 

	return 0;
}

(使用C语言详解)指针数组、数组指针、函数指针、函数指针的数组、指向函数指针数组的指针_数组_04

四、函数指针的数组(拓展)

1.概念

        函数指针的数组是C语言中一种非常有用的数据结构,本质是一个数组,它允许你存储多个函数指针,并且可以通过索引来调用这些函数。

2.作用

        存储和管理多个函数指针,使得程序能够在运行时根据需要调用不同的函数。它提供了一种灵活的方式来组织和调用多个函数,特别是在需要根据不同的条件或输入来选择执行不同函数的场景中非常有用。

3.应用场景

        1. 操作系统中的系统调用处理:操作系统需要处理各种不同的系统调用,例如进程创建、进程终止、文件操作等。函数指针数组可以用于存储这些系统调用的处理函数,使得操作系统可以根据系统调用的类型调用相应的处理函数。
        2. 事件处理:在某些程序中,例如图形用户界面(GUI)程序或游戏程序,程序需要处理各种事件,例如鼠标点击、键盘输入等。函数指针数组可以用于存储这些事件的处理函数,使得程序可以根据事件类型调用相应的处理函数。
        3. 软件工程中的模块化设计:函数指针数组可以用于存储一个模块中的所有函数,使得其他模块可以通过函数指针数组来调用该模块中的函数。这种设计方式可以使得程序结构更加清晰,方便程序的维护和扩展。

4.示例

以下代码,    

        pArr首先与方块[]结合,说明是5个元素的数组,去掉pArr[5],

        剩下的是每个元素的类型,每个元素的类型是指针指向一个函数,

        函数的参数是(int,int),返回类型是int

int Add(int x, int y) {
	return x + y;
} 

int main() {
	//函数指针
	int(*pAdd)(int, int) = Add;//&Add
	//函数指针的数组
	int (*pArr[5])(int, int);

	return 0;
}

(使用C语言详解)指针数组、数组指针、函数指针、函数指针的数组、指向函数指针数组的指针_数组_05

5.应用实验代码举例

以下代码,func_array 是一个函数指针数组,它包含了两个函数指针。这些指针分别指向 func1 和 func2 函数。在 main 函数中,我们通过索引 0 和 1 来调用这些函数。

#include <stdio.h>

// 定义一个函数指针类型
typedef void (*func_ptr)(void);

// 一个包含两个函数的数组
func_ptr func_array[] = {func1, func2};

// 数组中函数指针所指向的函数
void func1() {
    printf("Function 1 is called.\n");
}

void func2() {
    printf("Function 2 is called.\n");
}

int main() {
    // 通过索引调用数组中的函数
    func_array[0]();

    // 再次调用另一个函数
    func_array[1]();

    return 0;
}

(使用C语言详解)指针数组、数组指针、函数指针、函数指针的数组、指向函数指针数组的指针_函数指针_06

五、指向函数指针数组的指针(拓展)

1.概念

        指向函数指针数组的指针 本质是一个指针,它指向一个函数指针数组。

2.作用

        可以用来访问和操作函数指针数组中的元素。例如可以通过解引用来获取数组中的元素,或者通过递增或递减指针来遍历数组。

3.应用场景

        指向函数指针数组的指针在C语言中应用场景较少,我们更倾向于直接操作函数指针数组。
        1. 动态分配函数指针数组:当函数指针数组的大小需要在运行时动态确定时,可以使用指向函数指针数组的指针来动态分配内存。例如,可以使用`malloc`或`calloc`函数来分配一个适当大小的函数指针数组,并将其地址赋给指向函数指针数组的指针。
        2. 获取函数指针数组的大小:通过指向函数指针数组的指针,可以获取函数指针数组的大小。这可以通过递减指针并检查数组元素的值来实现,直到找到一个`NULL`值。
        3. 遍历函数指针数组:指向函数指针数组的指针可以用来遍历函数指针数组中的元素。这可以通过递增或递减指针来实现,从而调用数组中的每个函数。
        4. 模块化编程:在大型项目中,可能需要将不同的功能模块分配给不同的团队开发。使用指向函数指针数组的指针可以方便地将不同的功能模块集成到主程序中。通过调用不同的函数指针数组元素,可以实现对各个功能模块的调用。

4.示例

int Add(int x, int y) {
	return x + y;
} 

int main() {
	//函数指针
	int(*pAdd)(int, int) = Add;//&Add
	//函数指针的数组
	int (*pArr[5])(int, int);
    //指向函数指针数组的指针——基于函数指针的数组去写
	int (*(*ppArr)[5])(int, int)=&pArr;
	return 0;
}

(使用C语言详解)指针数组、数组指针、函数指针、函数指针的数组、指向函数指针数组的指针_函数指针_07

六、总结

        本文主要讲解了C语言中的五种指针类型:指针数组、数组指针、函数指针、函数指针的数组以及指向函数指针数组的指针。这些指针类型在C语言编程中有着广泛的应用,掌握它们对于深入理解C语言以及进行高效的C语言编程都具有重要意义。

  1. 指针数组是一种数组,其元素为指针;
  2. 数组指针则是一个指向数组的指针,它可以指向数组的首地址,也可以指向数组的任一元素。
  3. 函数指针则是指向函数的指针,通过它我们可以调用函数。
  4. 函数指针的数组则是一个数组,其元素为函数指针;
  5. 指向函数指针数组的指针则是一个指针,它指向函数指针数组。

总的来说,掌握这五种指针类型,可以帮助我们更好地理解C语言的底层原理,提高我们的编程效率,同时也可以为我们在日后的编程工作中遇到的一些复杂问题提供有效的解决方案。