指针不光可以指向数组,整型变量等data objects, 在C里面,指针也可以指向函数,指向函数的
指针有很多种用处,下面举例说明。
思考下面的问题,你想实现一个函数可以对任意数据类型进行排序,比如说,字符串,整数,浮点
数,甚至是结构体。具体的算法都用一样的,可以是冒泡排序,当然也可以是更复杂一些的算法,
比如 shell 或者快速排序。 为了演示,我们在这里使用简单的冒泡排序。
Sedgewick 有描述过怎样用C语言来实现冒泡排序,假设我们把函数名叫bubble(), 它可以是这个样
子的。 bubble1.c,
#include <stdio.h> int arr[10] = { 3, 6, 1, 2, 3, 8, 4, 1, 7, 2}; void bubble(int a[], int N); int main(void) { int i; putchar(‘\n‘); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } bubble(arr, 10); putchar(‘\n‘); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } system("pause"); return 0; } void bubble(int a[], int N) { int i, j, t; for (i = N-1; i >= 0; i--) { for (j = 1; j <= i; j++) { if (a[j-1] > a[j]) { t = a[j -1]; a[j-1] = a[j]; a[j] = t; } } } }
冒泡排序是一种比较简单的排序,这种算法扫描从第二到到最后一个,使用每一个元素和它之前的
那个元素比,如果前一个比当前元素要大,那么交换它们,这样,比较大的那一个就越来越靠近
数组的末尾,第一轮循环结束,最大的那个数将会移动到数组的末尾,下一轮循环将把第二大的
数列在最大的那个数前面,这样重复(元素个数减1)次,就会得到一个有序数组。
这里我们的函数有很大的局限性,只能比较整型数组里面的数据,为了能够比较任意类型,我们
先把比较这个过程从bubble()中拿出来,程序是这个样子的。
/* Separating the comparison function */ #include <stdio.h> int arr[10] = { 3, 6, 1, 2, 3, 8, 4, 1, 7, 2}; void bubble(int a[], int N); int compare(int m, int n); int main(void) { int i; putchar(‘\n‘); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } bubble(arr,10); putchar(‘\n‘); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } system("pause"); return 0; } void bubble(int a[], int N) { int i, j, t; for (i = N-1; i >= 0; i--) { for (j = 1; j <= i; j++) { if (compare(a[j-1], a[j])) { t = a[j-1]; a[j-1] = a[j]; a[j] = t; } } } } int compare(int m, int n) { return (m > n); }
如果我们的目的是可以排任意类型的数据,有一种搞法是这样的,使用void 指针,而不使用整型
数据类型,作为这个方向的开始,我们对上面函数作一些简答的修改,这里我们将指针指整型数据。
#include <stdio.h> int arr[10] = { 3, 6, 1, 2, 3, 8, 4, 1, 7, 2 }; void bubble(int *p, int N); int compare(int *m, int *n); int main(void) { int i; putchar(‘\n‘); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } bubble(arr, 10); putchar(‘\n‘); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } system("pause"); return 0; } void bubble(int *p, int N) { int i, j, t; for (i = N-1; i >= 0; i--) { for (j = 1; j <= i; j++) { if (compare(&p[j-1], &p[j])) { t = p[j-1]; p[j-1] = p[j]; p[j] = t; } } } } int compare(int *m, int *n) { return (*m > *n); }
注意我们修改到我地方,这里我们向bubble() 传递了一个指向integer的指针,下一步里,我们
将使用指向void 类型的指针,这样函数对数据类型变得更加的不敏感。
#include <stdio.h> #include <stdio.h> int arr[10] = {3, 6, 1, 2, 4, 8, 4, 1, 7, 2}; void bubble(int *p, int N); int compare(void *m, void *n); int main(void) { int i; putchar(‘\n‘); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } bubble(arr, 10); putchar(‘\n‘); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } system("pause"); return 0; } void bubble(int *p, int N) { int i, j, t; for (i = N-1; i >= 0; i--) { for (j = 1; j <= i; j++) { if (compare((void *)&p[j-1], (void *) &p[j])) { t = p[j - 1]; p[j-1] = p[j]; p[j] = t; } } } } int compare(void *m, void *n) { int *m1, *n1; m1 = (int *)m; n1 = (int *)n; return (*m1 > *n1); } 我们知道,数据的名字是一个指向其第一个元素(在数据段)地址的指针,同样的道理,函数名将指向函数代码
段的开始的地址。
指向函数的指针必须和函数参数的类型,个数以及返回值匹配,在这里我们这样定义
我们的函数指针:
int (*fptr)(const void *p1, const void *p2);
注意不能写成这样:
int *fptr(const void *p1, const void *p2);
如果写成这样,它的意思是给出了一个函数原型,它将返回一个指向int 的指针。这是因为
在C语言中括号() 比 * 的优先级要高。在* fptr 打个括号表示我们声明了一个函数指针。
这里我们修改一下bubble()的声明,增加第四个参数,一个指向合适类型的函数指针。
它的函数原型将变成这个样子:
void bubble(void *p, int width, int N, int (*fptr)(const void *, const void *));
当我们调用bubble的时候,将我们希望使用的比较函数名插进去。下面程序将会阐明这样方法的实现。
#include <stdio.h> #include <string.h> #define MAX_BUF 256 long arr[10] = {3, 6, 1, 2, 3, 8, 4, 1, 7, 2}; char arr2[5][20] = { " Mickey Mouse", " Donald Duck", " Minnie Mouse", " Goofy", " Ted Jensen" }; void bubble(void *p, int width, int n, int (*fptr)(const void *, const void *)); int compare_string(const void *m, const void *n); int compare_long(const void *m, const void *n); int main(void) { int i; puts("\nBefore Sorting:\n"); for (i = 0; i < 10; i++) /* show the long ints */ { printf("%ld ", arr[i]); } puts("\n"); for (i = 0; i < 5; i++) { printf("%s\n", arr2[i]); /* show the strings */ } bubble(arr, 4, 10, compare_long); /* sort the longs */ bubble(arr2, 20, 5, compare_string); /* sort the strings */ puts("\n\nAfter Sorting:\n"); for (i = 0; i < 10; i++) { printf("%d ", arr[i]); } puts("\n"); for (i = 0; i < 5; i++) /* show the sorted strings */ { printf("%s\n", arr2[i]); } system("pause"); return 0; } void bubble(void *p, int width, int N, int (*fptr)(const void *, const void *)) { int i, j, k; unsigned char buf[MAX_BUF]; unsigned char *bp = p; for (i = N - 1; i >= 0; i--) { for (j = 1; j <= i; j++) { k =fptr((void *)(bp + width*(j-1)), (void *)(bp + j *width)); } if (k > 0) { memcpy(buf, bp + width*(j-1), width); memcpy(bp + width*(j-1), bp + j*width, width); memcpy(bp + j*width, buf, width); } } } int compare_string(const void *m, const void *n) { char *m1 = (char *)m; char *n1 = (char *)n; return (strcmp(m1,n1)); } int compare_long(const void *m, const void *n) { long *m1, *n1; m1 = (long *)m; n1 = (long *) n; return (*m1 > *n1); }
原文:http://blog.csdn.net/robinsongsog/article/details/23062123