在将qsort函数应用于对指针数组与二维数组排序时,传递给compare函数的参数类型是不同的首先,我们举个简单的例子,先将qsort对整数数组排序:
1 int
2 cmp(const void *arg1, const void *arg2)
3 {
4 return (*(int *)arg1)-(*(int *)arg2);
5 }
6
7 int
8 main(int argc, char **argv)
9 {
10 int i;
11 int arr[] = {3, 1, 5, 2, 4};
12 qsort(arr, sizeof(arr)/sizeof(arr[0]), sizeof(int), cmp);
13 }
排序针对的是数组里的元素而言的,这里整数数组的元素就是整数,因此qsort的第三个参数就是sizeof(int),而传递给比较函数cmp的参数就是相对应的指向整数的指针
接着,我们来看看指针数组的情形:
1 int
2 cmp(const void *arg1, const void *arg2)
3 {
4 return strcmp((*(char **)arg1), (*(char **)arg2));
5 }
6
7 int
8 main(int argc, char **argv)
9 {
10 int i;
11 /* pointer array */
12 char *str[] = {"java", "c", "python", "perl"};
13 qsort(str, sizeof(str)/sizeof(str[0]), sizeof(char *), cmp);
14 }
这里的理解其实跟整数数组差不多,关键是抓住数组里元素的类型,既然称之为指针数组,那数组元素的类型自然就是指针,因此qsort的第三个参数就是sizeof(char *),而传递给比较函数cmp的参数就是相对应的指向指针的指针,这里即char **类型
二维数组的理解最为复杂,代码如下:
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4
5 int
6 cmp1(const void *arg1, const void *arg2)
7 {
8 return strcmp((*((char (*)[])arg1)), (*((char (*)[])arg2)));
9 }
10
11 int
12 cmp2(const void *arg1, const void *arg2)
13 {
14 return strcmp((char *)arg1, (char *)arg2);
15 }
16
17 int
18 main(int argc, char **argv)
19 {
20 int i;
21 char str1[4][8] = {"java", "c", "python", "peal"};
22 printf("COMPARE-FUNCTION-1\n");
23 qsort(str1, 4, sizeof(str1[0]), cmp1);
26
27 char str2[4][8] = {"java", "c", "python", "peal"};
28 printf("COMPARE-FUNCTION-2\n");
29 qsort(str2, 4, sizeof(str2[0]), cmp2);
34 }
这里cmp1与cmp2都能正常的工作(*^__^*) 嘻嘻……
还是按照上述方法来分析,抓住数组元素的类型来入手,二维数组实际上就是数组的数组,因此二维数组的元素类型就是一维数组,因此qsort的第三个参数就是sizeof(str1[0])或sizeof(str2[0]),那传递给比较函数的参数应该就是指向数组的指针,这点可以通过gdb设置断点来得到证实:
1 (gdb) p &str1[0]
2 $1 = (char (*)[8]) 0xbffff2cc
3 (gdb) p &str1[1]
4 $2 = (char (*)[8]) 0xbffff2d4
5
6 Breakpoint 2, cmp1 (arg1=0xbffff2cc, arg2=0xbffff2d4) at char_test2.c:8
7 8 return strcmp((*((char (*)[])arg1)), (*((char (*)[])arg2)));
8 (gdb) p arg1
9 $3 = (const void *) 0xbffff2cc
10 (gdb) p arg2
11 $4 = (const void *) 0xbffff2d4
12 (gdb) p *(char (*)[])arg1
13 $5 = "j"
14 (gdb) p *(char (*)[8])arg1
15 $6 = "java\000\000\000"
通过第2行与第9行的比较可以发现,比较函数的参数arg1其实就是&str1[0],类型为char (*)[],这也是为什么cmp1能正常工作的原因
那么cmp2呢,它为什么正确呢?
在cmp1中:
strcmp((*((char (*)[])arg1)), (*((char (*)[])arg2))); 这里传递给strcmp的参数之所以不会出错,是因为我们将arg1解地址操作获得一个数组,而数组名其实是指向数组首元素的指针,arg1既然是指向str1[0]这个一维数组的指针,而str1[0]本身其实就是指向这个一维数组的指针,也就是说arg1其实就是str1[0],因此cmp2能够正常工作
1 (gdb) p &str1[0]
2 $3 = (char (*)[8]) 0xbffff2cc
3 (gdb) p &str1[0][0]
4 $4 = 0xbffff2cc "java"
5 (gdb) p arg1
6 $5 = (const void *) 0xbffff2cc
7 (gdb) p (char *)arg1
8 $6 = 0xbffff2cc "java"
额...貌似越说越复杂的样子,不过这是我理解的过程,见谅...