在ANSI C中,qsort函數的原型是
#include <stdlib.h>
void qsort(void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *));
解釋:qsort函數對含有nmemb個元素的數組進行排序,而base指針指向數組的第一個元素。這個數組的元素個數由size指定。
compar函數對qsort的比較操作進行定義,所以可以定制數字的比較,字符串的比較,甚至結構體的比較,等等。compar的寫法見下面幾個例子。
一、使用qsort函數對普通數組進行排序。
代碼如下:
1 #include <stdio.h> 2 #include <stdlib.h> 3 4 int compare(const void *arg1, const void *arg2); 5 6 int 7 main(int argc, char** argv) 8 { 9 int i; 10 11 int arr[5] = { 13, 17, 2, 7, 71 }; 12 13 qsort(arr, sizeof(arr)/sizeof(arr[0]), sizeof(int), compare); 14 15 for (i = 0; i < 5; i++) { 16 printf("%d ", arr[i]); 17 } 18 printf("\n"); 19 } 20 21 22 int compare(const void *arg1, const void *arg2) { 23 int a = *(int*)arg1; 24 int b = *(int*)arg2; 25 if (a > b) { 26 return 1; 27 } 28 else if (a < b) { 29 return -1; 30 } 31 else { 32 return 0; 33 } 34 }
講一下參數compar的定義,由於qsort要求傳入一個函數指針,所以這個函數的名字我們可以自己設置,就跟其他形參的名字一樣,一般用cmp或者compare。
qsort函數把我們傳入的arr當做指向數組第一個元素的指針,所以相應地,在代碼第22行,形參表中的arg1和arg2,就是指向數組某個元素的指針。
在第23行和第24行,我們將void*轉換為int*,並且將指針解引用之后的值賦予a和b,進行比較。
如果a>b返回1,a<b返回-1,就意味着我們進行元素的升序排序,將元素從小到大進行排序。
二、使用qsort函數對指針數組進行排序。
代碼如下:
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 int compare(const void *arg1, const void *arg2); 6 7 int 8 main(int argc, char** argv) 9 { 10 int i; 11 12 char *arr[5] = { "i", "love", "c", "programming", "language" }; 13 14 qsort(arr, sizeof(arr)/sizeof(arr[0]), sizeof(char *), compare); 15 16 for (i = 0; i < 5; i++) { 17 printf("%s ", arr[i]); 18 } 19 printf("\n"); 20 /* getchar(); */ 21 } 22 23 int compare(const void *arg1, const void *arg2) { 24 char *a = *(char**)arg1; 25 char *b = *(char**)arg2; 26 int result = strcmp(a, b); 27 if (result > 0) { 28 return 1; 29 } 30 else if (result < 0) { 31 return -1; 32 } 33 else { 34 return 0; 35 } 36 }
與平常我們所用的數組相比,指針數組有些難理解,其實第12行的arr數組,它就是存放着5個指針,第1個元素存放指向常量字符串"i"的地址,第2個元素存放指向常量字符串"love"的地址,依此類推。
那么我們向qsort傳入arr之后,qsort將arr理解為指向數組中第一個元素的指針,所以第23行形參表中,arg1和arg2其實是指向“指向常量字符串的指針”的指針,是char**。而我們需要傳給strcmp這個字符串比較函數的,是“指向字符串的指針”,是char*,所以我們將void*轉換為char**,然后解引用,得到char*,賦予a和b。接下來使用strcmp對a和b進行比較。
三、使用qsort函數對指針數組進行排序。
代碼如下:
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 int compare(const void *arg1, const void *arg2); 6 7 int 8 main(int argc, char** argv) 9 { 10 int i; 11 12 char arr[5][16] = { "i", "love", "c", "programming", "language" }; 13 14 qsort(arr, sizeof(arr)/sizeof(arr[0]), sizeof(arr[0]), compare); 15 printf("%s\n", arr[0]); 16 for (i = 0; i < 5; i++) { 17 printf("%s ", arr[i]); 18 } 19 printf("\n"); 20 /* getchar(); */ 21 } 22 23 int compare(const void *arg1, const void *arg2) { 24 char *a = (char*)arg1; 25 char *b = (char*)arg2; 26 int result = strcmp(a, b); 27 if (result > 0) { 28 return 1; 29 } 30 else if (result < 0) { 31 return -1; 32 } 33 else { 34 return 0; 35 } 36 }
二維數組比較常見,但是在qsort函數中要對這個數組中的元素進行排序,理解起來稍微有些難度。不過一步一步分析,思路也就自然了。
這里對二維數組進行排序,其實是對二維數組的第二維中存放的字符串進行排序。所以在第14行對qsort函數的調用中,第二個參數是待排元素的個數(5個),第三個參數是待排元素的大小(16)。
我們將arr傳入qsort函數,qsort函數將arr理解為指向數組第一個元素的指針,arr的第一個元素是arr[0][0],所以參數arg1和arg2指的是指向"a[i][0]"的指針,我們知道,a[i][0]是字符,就是char,所以arg1和arg2指的是char *。我們將void*轉換為char*,賦予a和b,調用strcmp函數對a和b進行比較。
就是這樣。