【问题标题】:QSorting a malloc'd array of structures?QSorting一个malloc的结构数组?
【发布时间】:2011-03-08 04:03:16
【问题描述】:

我在 C 中为我的 qsort 提供了这个比较器功能,但无论我尝试什么,我似乎都遇到了分段错误...

int textCompare ( const void * a, const void * b ){
    const char **x =(const char**)a;
    const char **y =(const char**)b;
    return strcmp(*x, *y);
}

这是我的 qsort 调用:其中 message** mList = malloc(INITIAL_CAPACITY * sizeof(message));count 是跟踪最后一个元素的整数。 message 只是一个 typedef 结构,它包含一个 int 和一个指向 char 的指针。我有 67% 的把握正确调用 qsort,谁能指出我正确的方向?

qsort (*mList, count, sizeof(message), textCompare);

[编辑] 我声明 message*** 而不是 message* 的原因是因为我试图初始化一个指向结构的指针“数组”;除非我走错路了?

【问题讨论】:

  • 由于消息显然不是指向 char 指针的指针,因此问题可能在于您的比较器应该比较消息结构而不是指向字符串的指针。此外,您的内存分配在 LHS 上的星号太多或在 RHS 上的大小错误。或者,也许,mList 是您的函数的参数,但是分配行具有误导性;你会做*mList = malloc(INITIAL_CAPACITY * sizeof(message));
  • 我声明 message*** 而不是 message* 的原因是因为我试图初始化一个指向结构的指针“数组”;除非我走错路了?

标签: c pointers struct qsort


【解决方案1】:

如果您确实想要对指向消息结构的指针数组进行排序,那么您需要使用它

message **mlist = (message **)malloc(INITIAL_CAPACITY * sizeof(message *));

然后你必须为数组中的指针指向的每条消息分配内存。

for(int i=0; i<INITIAL_CAPACITY; i++) {
  mlist[i] = (message *)malloc(sizeof(message));
  /*  initialize the members here  */
  mlist[i]->int = get_int();
  mlist[i]->char = get_char();  
  count++
  if(count >= NUM_TO_FILL_RIGHT_NOW)
   break;   
} 

现在您可以对指针数组而非结构本身进行排序。

int textCompare( const void *a, const void *b ) {
  message *m1 = *(message **)a;
  message *m2 = *(message **)b;
  return strcmp(m1->char, m2->char);
}

现在在指针数组上调用 qsort

qsort( mlist, count, sizeof(message *), textCompare );  

使用此方法,指针位于连续内存中(理论上),但结构本身会根据需要单独分配。此外,由于被复制对象的大小,排序指针通常比排序结构更快。指针在 64 位机器上是 8 个字节,在 32 位机器上是 4 个字节,你的结构实际上可能比这小,但典型的结构会比指针大。

【讨论】:

    【解决方案2】:

    我不确定您调用 malloc() 是否为您想要使用的内存分配了正确类型的内存。您正在声明一个指针数组,然后依次指向某个(可能的)指针数组,但似乎您正在为结构本身的实际大小保留内存,即,您正在为数组保留内存消息,而不是指向消息的指针数组。例如,如果您取消引用 mlist,那么结果指针指向的是什么?它是指向一个单独的消息结构,还是一个消息结构数组(即,你有一些消息结构的二维数组,其中 mlist[0] 到 mlist[n] 每个都代表一个指向消息数组的指针在大小任意长度的堆上)?如果它不应该指向任何东西,而应该是一个实际的消息结构,那么你的调用应该更像:

    message* mlist = malloc(INITIAL_CAPACITY * sizeof(message));
    

    而不是 mlist 的类型为 message**

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      @Jason 和@Tim 都给出了正确答案。这是一个正确的工作程序,可以证明他们的答案。

      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      
      typedef struct message {
        int i;
        char *p;
      } message;
      
      int textCompare(const void *a, const void *b) {
        const message *ma = a;
        const message *mb = b;
        return strcmp(ma->p, mb->p);
      }
      
      int main()
      {
        int i;
        message* mList = malloc(10 * sizeof(message));
        mList[0].i = 0; mList[0].p = "zero";
        mList[1].i = 1; mList[1].p = "one";
        mList[2].i = 2; mList[2].p = "two";
      
        qsort(mList, 3, sizeof(message), textCompare);
      
        for(i = 0; i < 3; i++) {
          printf("%d %s\n", mList[i].i, mList[i].p);
        }
        return 0;
      }
      

      注意malloc 调用的模式。分配T类型的数组:

      T* var = malloc(array_size * sizeof(T));
      

      看看声明中只有一个*,而 sizeof() 运算符比这少了一颗星。有些人更喜欢这种形式:

      T* var = malloc(array_size * sizeof *var);
      

      这样你只需要指定一次类型。这对于复杂类型特别有用。

      另外,请注意malloc 的结果没有强制转换。

      另外,请注意 qsort() 的第一个参数的类型如何匹配比较函数中转换参数的类型。在这种特定情况下,它们都是message*

      您可能会发现此 qsort 调用更易于理解和维护:

      qsort(mList, 3, sizeof(*mList), textCompare);
      

      【讨论】:

      • OP 想要排序指针数组,而不是结构数组。请参阅已接受的答案以获取正确答案。
      猜你喜欢
      • 2015-02-12
      • 1970-01-01
      • 1970-01-01
      • 2015-07-30
      • 1970-01-01
      • 2011-07-24
      • 2016-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多