【问题标题】:C qsort() with dynamic n by 2 multi-dimensional arrayC qsort() 与动态 n × 2 多维数组
【发布时间】:2013-06-16 15:11:56
【问题描述】:

首先,我定义了一个 2 列 10 行的动态数组。此处将整数number设置为10为例。

int** array;
int number = 10;

array = malloc(number * sizeof(int*));

for (i = 0; i < number; i++)
    array[i] = malloc(2 * sizeof(int));

然后我尝试在上面使用qsort()

qsort( array, number, sizeof array[0], compare );

这是我的比较功能。它按第一列中的整数值排序,然后按第二列排序,同时保留第一列中的顺序。例如。 “0 2, 1 7, 0 1”将变为“0 1, 0 2, 1 7”。

int compare ( const void *pa, const void *pb ) {
    int (*a)[1] = pa;
    int (*b)[1] = pb;
    if ( (a[0][0] < b[0][0]) || (a[0][0] == b[0][0])&&(a[1][0] < b[1][0]) ) return -1;
    if ( (a[0][0] > b[0][0]) || (a[0][0] == b[0][0])&&(a[1][0] > b[1][0]) ) return +1;
    return 0;
}

问题

这适用于静态数组。我知道它现在不起作用,因为我有一个动态数组,它是一个指针数组。

如何调整此代码以使用动态创建的多维数组?

【问题讨论】:

  • 指向数组的指针!= 指向指针的指针。

标签: c dynamic-arrays qsort


【解决方案1】:

由于您现在有一个指针数组,所以比较函数的参数将是指向指针的指针。像这样使用它们:

int *const *a = pa;
int *const *b = pb;

现在您将ab 作为指向要排序的数组的两个指针。每一个都指向排序函数要求您检查的单个元素。您可以使用*a*ba[0]b[0] 访问这些元素,但永远不要使用a[1]b[1]。如果排序函数要求您比较数组中的第一个元素 (*a) 和数组中的第五个元素 (*b),a[1]b[1] 是数组的第二个和第六个元素 - 完全与您应该进行的比较无关。

在第一级取消引用之后,您可以做任何您需要做的事情来检查被比较的元素。由于您的数组元素本身是指向数组的指针(每个数组有 2 个 int),因此 ints 可以作为 a[0][0] a[0][1] b[0][0] b[0][1] 访问。请注意,这与您的a[1][0]b[1][0] 的顺序相反。

将它们写为(*a)[0] 会提醒您,第一级间接是“仅单元素访问”指针。我不确定这是否会让整个事情变得更清楚。

【讨论】:

    【解决方案2】:

    示例代码

    #include <stdio.h>
    #include <stdlib.h>
    
    int compare ( const void *pa, const void *pb ) {
        const int *a = *(const int **)pa;
        const int *b = *(const int **)pb;
        if(a[0] == b[0])
            return a[1] - b[1];
        else
            return a[0] - b[0];
    }
    /*
    #define NUMCMP(x,y) (((x) < (y)) ? -1 : ((x) > (y)) ? 1 : 0)
    
    int compare ( const void *pa, const void *pb ) {
        const int (*a)[2] = *(const int (**)[2])pa;
        const int (*b)[2] = *(const int (**)[2])pb;
        int tmp;
        if((tmp=NUMCMP((*a)[0], (*b)[0]))==0)
            return NUMCMP((*a)[1], (*b)[1]);
        else
            return tmp;
    }
    */    
    int main(void){
        int **array;
        int number = 10;
        int i;
    
        array = malloc(number * sizeof(int*));
        for (i = 0; i < number; i++){
            array[i] = malloc(2 * sizeof(int));
            array[i][0] = rand()%20;
            array[i][1] = rand()%20;
        }
        for(i = 0;i < number;++i)
            printf("%2d, %2d\n", array[i][0], array[i][1]);
    
        printf("\n");
    
        qsort(array, number, sizeof array[0], compare);
    
        for(i = 0;i < number;++i)
            printf("%2d, %2d\n", array[i][0], array[i][1]);
    
        return 0;
    }
    

    什么 *(const int **)pa

    数组 = {(int *), (int *), (int *), ... , (int *) }

    qsort 需要每个元素的地址为元素(用于交换等,因为元素的大小和个数以及起始地址因为只有给定的信息)。

    例如 &(int *), &(int *)

    所以(int **) 传递给函数比较。

    调用 compare(int **, int **) &amp;(int*) 表示 arg int**

    比较函数原型是cmp(const void*, const void*)

    cast (const int**)pa 被强制转换为传递的原始指针。

    *((const int **)pa) 是取消引用原始元素指针(int*)

    【讨论】:

    • 请注意,如果a 中的值很大且为正,而b 中的值很大且为负(反之亦然),return a[1] - b[1];(和类似的表达式)是危险的。您可能会得到算术溢出,这会导致未定义的行为。对于大多数合理的数据集,这不会是一个问题。但是,您应该意识到这个问题。
    • @JonathanLeffler 好点,谢谢。但请注意,在这种情况下,0 个或多个值每个都是 rand 的值。
    • 感谢您的解释!还有@JonathanLeffler - 谢谢你的意见+1。
    • @hacks ,例如 int *p1 = malloc(2*sizeof(int)); int (*p2)[2] = malloc(2*sizeof(int)); --> func((void*)&amp;p1) func((void*)&amp;p2) :两者都与指向 func 的另一种类型的指针相同。它可以被解释为任何一种方式。
    • @hacks ,它将接收作为 void * 而不是 int ** 的比较函数。 pbpa 的类型仅为 void * 而不是 int **
    【解决方案3】:

    对于这个静态数组,sizeof array[0] 将是“2 * sizeof(int)”。

    int array[10][2];
    

    sizeof array[0] 将是“sizeof(int*)”,对于这个指向指针的指针。 sizeof array[0][0] 将是“sizeof(int)”,对于这个指向指针的指针。

    int **array;
    

    所以,首先你不能使用“qsort(array, number, sizeof array[0], compare);”在指针到指针实现的情况下。

    【讨论】:

      【解决方案4】:

      我在寻找我的同上问题时遇到了这个线程,最后我最终做了以下事情。

      static int compareMatrixElements(const void *p1, const void *p2)
      {
          return ((*(int const *) p1) - (*(int const *) p2));
      }
      
      void sortMatrix(int** matrix, int r, int c)
      {
          int sort_matrix[r][c];
      
          for(int i = 0; i < r; i++) {
      
              memcpy(sort_matrix[i], matrix[i], c * sizeof(int));
          }
      
          qsort(sort_matrix, r*c, sizeof(int), compareMatrixElements);
      
          for(int i = 0; i < r; i++) {
      
              memcpy(matrix[i], sort_matrix[i], c * sizeof(int));
          }
      }
      

      在我上面的代码中,我直接使用了 qsort API,可以在连续内存上使用这个 api 或任何其他排序算法,但是如果你有一个矩阵,其行是指向其列的内存的指针(比如在我的情况下以及在这个线程的问题中描述)。因此,我将这样的矩阵复制到一个连续的内存中,在该连续内存上运行排序并将排序后的元素复制回矩阵。

      上述解决方案对我有用,我认为它可能对其他人有帮助,所以我发布了它,并提出任何改进建议。

      【讨论】:

        【解决方案5】:
        const int *a = *(const int **)pa;
        const int *b = *(const int **)pb;
        

        @BLUEPIXY,这是不正确的。 够了

        const int *a = pa;
        const int *b = pb;
        

        因为 pa 是 const void * (array[0]) 并且它很好地转换为 const int *

        【讨论】:

          【解决方案6】:
          const int (*a)[2] = *(const int (**)[2])pa;
          const int (*b)[2] = *(const int (**)[2])pb;
          

          @BLUEPIXY,这是不正确的。够了

          const int (*a)[2] = (int(*)[])pa;
          const int (*b)[2] = (int(*)[])pb;
          

          【讨论】:

            猜你喜欢
            • 2018-05-16
            • 2011-02-16
            • 1970-01-01
            • 2017-03-30
            • 2012-02-02
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多