函数指针是控制程序执行的一种非常灵活的方法。在本节中,我们会通过将比较函数传递给排序函数来说明这种能力。排序函数通过比较数组的元素来判断是否交换数组元素,比较决定了数组是按升序还是降序(或者其他排序策略)排列。通过传递一个函数来控制比较,排序函数会变得更灵活。传递不同的比较函数可以让同一个排序函数以不同的方式工作。
我们使用的比较函数根据数组的元素大小写决定排序顺序。下面的compare
和compareIgnoreCase
会根据大小写比较字符串。在用strcmp
函数比较字符串之前,compareIgnoreCase
函数会先把字符串转换成小写。5.2.1节中已经讨论过strcmp
函数了。stringToLower
函数返回动态分配内存的指针,这意味着一旦不需要就应该将其释放掉。
int compare(const char* s1, const char* s2) {
return strcmp(s1,s2);
}
int compareIgnoreCase(const char* s1, const char* s2) {
char* t1 = stringToLower(s1);
char* t2 = stringToLower(s2);
int result = strcmp(t1, t2);
free(t1);
free(t2);
return result;
}
stringToLower
函数如下所示,它将传递进来的字符串用小写的形式返回:
char* stringToLower(const char* string) {
char *tmp = (char*) malloc(strlen(string) + 1);
char *start = tmp;
while (*string != 0) {
*tmp++ = tolower(*string++);
}
*tmp = 0;
return start;
}
使用如下的类型定义声明我们要使用的函数指针:
typedef int (fptrOperation)(const char*, const char*);
下面的sort
函数的实现基于冒泡排序算法,我们将数组地址、数组长度以及一个控制排序的函数指针传递给它。在if
语句中,调用传递进来的函数并传递数组的两个元素,它会判断这两个元素是否需要交换。
void sort(char *array[], int size, fptrOperation operation) {
int swap = 1;
while(swap) {
swap = 0;
for(int i=0; i<size-1; i++) {
if(operation(array[i],array[i+1]) > 0){
swap = 1;
char *tmp = array[i];
array[i] = array[i+1];
array[i+1] = tmp;
}
}
}
}
打印函数会显示数组的内容:
void displayNames(char* names[], int size) {
for(int i=0; i<size; i++) {
printf("%s ",names[i]);
}
printf("\n");
}
我们可以用两个比较函数中的任意一个作为参数调用sort
函数。下面用compare
函数进行区分大小写的排序:
char* names[] = {"Bob", "Ted", "Carol", "Alice", "alice"};
sort(names,5,compare);
displayNames(names,5);
输出如下:
Alice Bob Carol Ted alice
如果使用compareIgnoreCase
函数,输出则是这样:
Alice alice Bob Carol Ted
这样sort
函数就灵活得多了,我们可以设计并传递自己想要的任意简单或复杂的操作来控制排序,而不需要针对不同的排序需求写不同的排序函数。