[Tips][Original] qsort应用于指针数组与二维数组(字符)的差异
在将qsort函数应用于对指针数组与二维数组排序时,传递给compare函数的参数类型是不同的
首先,我们举个简单的例子,先将qsort对整数数组排序:
接着,我们来看看指针数组的情形:
二维数组的理解最为复杂,代码如下:
还是按照上述方法来分析,抓住数组元素的类型来入手,二维数组实际上就是数组的数组,因此二维数组的元素类型就是一维数组,因此qsort的第三个参数就是sizeof(str1[0])或sizeof(str2[0]),那传递给比较函数的参数应该就是指向数组的指针,这点可以通过gdb设置断点来得到证实:
那么cmp2呢,它为什么正确呢?
在cmp1中: strcmp((*((char (*)[])arg1)), (*((char (*)[])arg2))); 这里传递给strcmp的参数之所以不会出错,是因为我们将arg1解地址操作获得一个数组,而数组名其实是指向数组首元素的指针,arg1既然是指向str1[0]这个一维数组的指针,而str1[0]本身其实就是指向这个一维数组的指针,也就是说arg1其实就是str1[0],因此cmp2能够正常工作
额...貌似越说越复杂的样子,不过这是我理解的过程,见谅...
首先,我们举个简单的例子,先将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的参数就是相对应的指向整数的指针
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 }
接着,我们来看看指针数组的情形:
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 **类型
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 }
二维数组的理解最为复杂,代码如下:
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都能正常的工作(*^__^*) 嘻嘻……
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 }
还是按照上述方法来分析,抓住数组元素的类型来入手,二维数组实际上就是数组的数组,因此二维数组的元素类型就是一维数组,因此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能正常工作的原因
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 "
那么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 "
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 "
额...貌似越说越复杂的样子,不过这是我理解的过程,见谅...