结构体 - 使用qsort对C字符串进行排序

3

我正在对一堆IP地址进行排序,但是它们的顺序似乎不正确。我不确定问题出在哪里。

66.249.71.3      
190.148.164.245  
207.46.232.182   
190.148.164.245  
190.148.164.245  
202.154.114.253
190.148.164.245  
190.148.164.245  
66.249.71.3      
190.148.164.245  
202.154.114.253

这是我排序它们的方式。
typedef struct {
    char *ip;
} mystruct;

/* qsort */
int struct_cmp(const void *a, const void *b)
{
    mystruct *ia = (mystruct *)a;
    mystruct *ib = (mystruct *)b;
    return strcmp(ia->ip, ib->ip);
} 
...
qsort(a_struct, 11, sizeof(mystruct*), struct_cmp);
for(..){
    printf("%s\n",a_struct[i]->ip);
}

任何帮助将不胜感激。谢谢。

你提供了输入还是输出的样例? - FrustratedWithFormsDesigner
3个回答

7
你有一个指向mystruct的指针数组,但使用这个比较函数的qsort期望一个简单的mystruct数组。为了对mystruct*数组进行排序,您需要在比较函数中添加另一级间接性:
int struct_cmp(const void *a, const void *b) {
    mystruct *ia = *(mystruct **)a;
    mystruct *ib = *(mystruct **)b;
    return strcmp(ia->ip, ib->ip);
}

Josh,如果你尝试在调试器中运行代码,或者在struct_cmp()函数内添加一个printf()调用,你会发现当指针错误时IP地址是垃圾值。因此,一种好的调试技巧是:当事情变得奇怪时,请确保你的指针指向你认为它们指向的位置! :-) - steveha
吹毛求疵:你在这里没有使用const-correct,因为你正在强制转换constness。应该是mystruct *ia = *(mystruct * const *)a等等,尽管在这种情况下没有造成任何伤害。 - Adam Rosenfield

3
你正在将IP地址作为字符串进行排序。如果它们被标准化,这种方法实际上是可行的:如果你想要它起效,应该使用066.249.071.003而不是66.249.71.3
我认为你最好使用一个函数将点分IP地址转换为32位整数,然后使用生成的整数作为排序键来进行排序。
你可以使用inet_addr()来完成此转换。将以下代码添加到你的程序中即可:
#include <arpa/inet.h>

这里有关于it技术的文档


我同意我错过了主要问题。但是一旦他使用sth的答案,由于这个问题,他会看到排序很奇怪,所以把两个答案结合起来才是最好的解决方案。 - steveha

2

至少有两种方法可以修复排序代码。一种是修改比较函数以匹配对qsort()的调用;另一种是修复对qsort()的调用以匹配比较器。正确的修复取决于数组的定义 - 但最简单的声明是结构数组(而不是结构指针的数组)。因此,该工作代码使用原始比较器但不同的qsort()调用:

#include <stdlib.h>
#include <stdio.h>

typedef struct {
    char *ip;
} mystruct;

static mystruct a_struct[] =
{
    "66.249.71.3",
    "190.148.164.245",
    "207.46.232.182",
    "190.148.164.245",
    "190.148.164.245",
    "202.154.114.253",
    "190.148.164.245",
    "190.148.164.245",
    "66.249.71.3",
    "190.148.164.245",
    "202.154.114.253",
};

/* qsort */
static int struct_cmp(const void *a, const void *b)
{
    mystruct *ia = (mystruct *)a;
    mystruct *ib = (mystruct *)b;
    return strcmp(ia->ip, ib->ip);
}

static void print_list(mystruct *list, int n)
{
    int i;
    for (i = 0; i < n; i++)
        printf("%2d: %s\n", i, list[i].ip);
}

#define DIM(x)  (sizeof(x)/sizeof(*(x)))

int main(void)
{
    print_list(a_struct, DIM(a_struct));
    qsort(a_struct, DIM(a_struct), sizeof(mystruct), struct_cmp);
    print_list(a_struct, DIM(a_struct));
}

现在我们只剩下一个按字母数字顺序排序的数组,其中所有的“190.x.y.z”地址都出现在其他地址之前等等。要解决这个问题需要使用更复杂的比较器-其中一种解决方案被steveha在他的答案中描述。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接