A Za, A Za, Fighting...

坚信:勤能补拙

[Tips][Original] qsort应用于指针数组与二维数组(字符)的差异

在将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[] = {31524};
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, 4sizeof(str1[0]), cmp1);
26 
27     char str2[4][8= {"java""c""python""peal"};
28     printf("COMPARE-FUNCTION-2\n");
29     qsort(str2, 4sizeof(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"

额...貌似越说越复杂的样子,不过这是我理解的过程,见谅...

posted on 2010-10-29 15:09 simplyzhao 阅读(2113) 评论(0)  编辑 收藏 引用 所属分类: A_排序


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


导航

<2010年8月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

常用链接

留言簿(1)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜