C 编程中的函数指针与示例
指针为我们仅限于返回一个值的“C”函数提供了极大的可能性。有了指针参数,我们的函数现在可以处理实际数据而不是数据的副本。
为了修改变量的实际值,调用语句将地址传递给函数中的指针参数。
在此教程,你会学到-
- 函数指针示例
- 带有数组参数的函数
- 返回数组的函数
- 函数指针
- 函数指针数组
- 使用空指针的函数
- 作为参数的函数指针
函数指针示例
例如,下一个程序交换两个两个值:
void swap (int *a, int *b); int main() { int m = 25; int n = 100; printf("m is %d, n is %d\n", m, n); swap(&m, &n); printf("m is %d, n is %d\n", m, n); return 0;} void swap (int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp;} }
输出:
m is 25, n is 100 m is 100, n is 25
程序交换实际变量值,因为函数使用指针通过地址访问它们。这里我们将讨论程序过程:
- 我们声明了负责交换两个变量值的函数,它接受两个整数指针作为参数,调用时返回任意值。
- 在主函数中,我们声明并初始化了两个整数变量(‘m’和‘n’),然后我们分别打印它们的值。
- 我们调用 swap() 函数,使用 &符号将两个变量的地址作为参数传递。之后,我们打印变量的新交换值。
- 这里我们定义swap()函数内容,它以两个整型变量地址作为参数,并声明一个临时整型变量,作为第三个存储框保存其中一个值变量,该值变量将被放入第二个变量中。李>
- 将“a”指向的第一个变量的内容保存在临时变量中。
- 将b指向的第二个变量存储在a指向的第一个变量中。
- 用保存在临时变量中的第一个变量的值更新第二个变量(由 b 指向)。
带有数组参数的函数
在 C 中,我们不能将数组按值传递给函数。而数组名是一个指针(地址),所以我们只需将数组名传递给函数,这意味着将指针传递给数组。
例如,我们考虑以下程序:
int add_array (int *a, int num_elements); int main() { int Tab[5] = {100, 220, 37, 16, 98}; printf("Total summation is %d\n", add_array(Tab, 5)); return 0;} int add_array (int *p, int size) { int total = 0; int k; for (k = 0; k < size; k++) { total += p[k]; /* it is equivalent to total +=*p ;p++; */} return (total);}
输出:
Total summation is 471
在这里,我们将详细解释程序代码
- 我们声明并定义了 add_array() 函数,该函数接受一个数组地址(指针)及其元素编号作为参数,并返回这些元素的总和。指针用于迭代数组元素(使用 p[k] 表示法),我们将总和累积在一个局部变量中,该变量将在迭代整个元素数组后返回。
- 我们声明并初始化一个包含五个整数元素的整数数组。我们通过将数组名称(作为地址)和数组大小传递给 add_array() 来打印总和 调用函数作为参数。
返回数组的函数
在 C 中,我们可以返回一个指向数组的指针,如下程序所示:
#include <stdio.h> int * build_array(); int main() { int *a; a = build_array(); /* get first 5 even numbers */ for (k = 0; k < 5; k++) printf("%d\n", a[k]); return 0;} int * build_array() { static int Tab[5]={1,2,3,4,5}; return (Tab);}
输出:
1 2 3 4 5
在这里,我们将讨论程序细节
- 我们定义并声明了一个函数,该函数返回一个包含整数值且不带任何参数的数组地址。
- 我们声明一个整数指针,它接收函数调用后构建的完整数组,并通过迭代整个五元素数组来打印其内容。
请注意,定义了一个指针而不是数组来存储函数返回的数组地址。另请注意,当从函数返回局部变量时,我们必须在函数中将其声明为静态。
函数指针
正如我们从定义中知道的那样,指针指向任何内存位置的地址,它们也可以作为内存中的函数指向可执行代码的开头。
指向函数的指针用 * 声明,一般声明它的声明是:
return_type (*function_name)(arguments)
您必须记住,(*function_name) 周围的括号很重要,因为没有它们,编译器会认为 function_name 返回的是 return_type 的指针。
定义函数指针后,我们必须将其分配给函数。例如下一个程序声明一个普通函数,定义一个函数指针,将函数指针赋值给普通函数,然后通过指针调用函数:
#include <stdio.h> void Hi_function (int times); /* function */ int main() { void (*function_ptr)(int); /* function pointer Declaration */ function_ptr = Hi_function; /* pointer assignment */ function_ptr (3); /* function call */ return 0;} void Hi_function (int times) { int k; for (k = 0; k < times; k++) printf("Hi\n");}
输出:
Hi Hi Hi
- 我们定义并声明了一个标准函数,该函数在调用函数时打印由参数 times 指示的 Hi 文本 k 次
- 我们定义了一个指针函数(带有它的特殊声明),它接受一个整数参数并且不返回任何内容。
- 我们用 Hi_function 初始化我们的指针函数,这意味着指针指向 Hi_function()。
- 我们不是通过在函数名上加上参数来调用标准函数,而是通过传递数字 3 作为参数来调用指针函数,就是这样!
请记住,函数名称指向可执行代码的起始地址,就像指向其第一个元素的数组名称一样。因此,function_ptr =&Hi_function 和 (*funptr)(3) 等指令是正确的。
注意:在函数赋值和函数调用过程中插入地址运算符 &和间接运算符 * 并不重要。
函数指针数组
函数指针数组可以起到 switch 或 if 语句的作用来做出决定,如下一个程序:
#include <stdio.h> int sum(int num1, int num2); int sub(int num1, int num2); int mult(int num1, int num2); int div(int num1, int num2); int main() { int x, y, choice, result; int (*ope[4])(int, int); ope[0] = sum; ope[1] = sub; ope[2] = mult; ope[3] = div; printf("Enter two integer numbers: "); scanf("%d%d", &x, &y); printf("Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: "); scanf("%d", &choice); result = ope[choice](x, y); printf("%d", result); return 0;} int sum(int x, int y) {return(x + y);} int sub(int x, int y) {return(x - y);} int mult(int x, int y) {return(x * y);} int div(int x, int y) {if (y != 0) return (x / y); else return 0;}
Enter two integer numbers: 13 48 Enter 0 to sum, 1 to subtract, 2 to multiply, or 3 to divide: 2 624
在这里,我们讨论一下程序细节:
- 我们声明并定义了四个函数,它们接受两个整数参数并返回一个整数值。这些函数对用户调用哪个函数的两个参数进行加、减、乘和除。
- 我们声明了 4 个整数来分别处理操作数、操作类型和结果。此外,我们声明了一个包含四个函数指针的数组。数组元素的每个函数指针接受两个整数参数并返回一个整数值。
- 我们使用已经声明的函数来分配和初始化每个数组元素。例如,第三个函数指针的第三个元素将指向乘法运算函数。
- 我们从使用键盘输入的用户那里寻找操作数和操作类型。
- 我们用参数调用适当的数组元素(函数指针),并存储适当函数生成的结果。
指令 int (*ope[4])(int, int);定义函数指针数组。每个数组元素必须有相同的参数和返回类型。
语句 result =ope[choice](x, y);根据用户的选择运行相应的函数。输入的两个整数是传递给函数的参数。
使用 void 指针的函数
在函数声明期间使用 void 指针。我们使用 void * 返回类型允许返回任何类型。如果我们假设我们的参数在传递给函数时不会改变,我们将其声明为 const。
例如:
void * cube (const void *);
考虑以下程序:
#include <stdio.h> void* cube (const void* num); int main() { int x, cube_int; x = 4; cube_int = cube (&x); printf("%d cubed is %d\n", x, cube_int); return 0;} void* cube (const void *num) { int result; result = (*(int *)num) * (*(int *)num) * (*(int *)num); return result;}
结果:
4 cubed is 64
在这里,我们将讨论程序细节:
- 我们定义并声明了一个函数,该函数返回一个整数值并获取一个没有特定数据类型的不可更改变量的地址。我们计算 num 指针指向的内容变量 (x) 的立方体值,由于它是一个 void 指针,我们必须使用特定的符号 (* datatype) 指针将其类型转换为整数数据类型,然后返回立方体值。
- 我们声明操作数和结果变量。此外,我们用值“4”初始化我们的操作数。
- 我们通过传递操作数地址调用cube函数,并在result变量中处理返回值
函数指针作为参数
通过将函数指针作为参数传递给另一个函数来利用函数指针的另一种方法有时称为“回调函数”,因为接收函数“回调它”。
在 stdlib.h 头文件中,快速排序“qsort() ”函数使用这种技术,这是一种专门用于对数组进行排序的算法。
void qsort(void *base, size_t num, size_t width, int (*compare)(const void *, const void *))
- void *base :指向数组的 void 指针。
- size_t num :数组元素编号。
- size_t width 元素大小。
- int (*compare (const void *, const void *) :由两个参数组成的函数指针,当参数值相同时返回0,<0表示arg1在arg2之前,>0表示arg1在arg2之后.
以下程序使用 qsort() 函数将整数数组从小到大排序:
#include <stdio.h> #include <stdlib.h> int compare (const void *, const void *); int main() { int arr[5] = {52, 14, 50, 48, 13}; int num, width, i; num = sizeof(arr)/sizeof(arr[0]); width = sizeof(arr[0]); qsort((void *)arr, num, width, compare); for (i = 0; i < 5; i++) printf("%d ", arr[ i ]); return 0;} int compare (const void *elem1, const void *elem2) { if ((*(int *)elem1) == (*(int *)elem2)) return 0; else if ((*(int *)elem1) < (*(int *)elem2)) return -1; else return 1;}
结果:
13 14 48 50 52
在这里,我们将讨论程序细节:
- 我们定义了由两个参数组成的比较函数,当参数具有相同的值时返回0,当arg1在arg2之前时返回<0,当arg1在arg2之后时返回>0。参数是一个void指针类型转换为适当的数组数据类型(整数)
- 我们定义并初始化一个整数数组,数组大小存放在num中 变量和每个数组元素的大小使用 sizeof() 预定义的 C 运算符存储在宽度变量中。
- 我们称 qsort 函数并传递用户先前定义的数组名称、大小、宽度和比较函数,以便按升序对我们的数组进行排序。比较将通过每次迭代取两个数组元素来执行,直到整个数组被排序。
- 我们打印数组元素,以确保我们的数组通过使用 for 循环迭代整个数组得到良好排序。
C语言