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

[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[]  =  { 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 "

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

你可能感兴趣的:([Tips][Original] qsort应用于指针数组与二维数组(字符)的差异)