在將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行的比較可以發(fā)現,比較函數的參數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"
額...貌似越說越復雜的樣子,不過這是我理解的過程,見諒...
]]>