无法在 C 中使用 qsort 对 dirent 进行排序

Unable to sort dirent with qsort in C

我在用 C 语言对 dirent 结构进行排序时遇到问题。我已经尝试了所有方法,但无法让我的结构数组的值出现在我的比较中。我的代码如下所示:

void printSortedNames(){

    struct dirent **file_list = (dirent**)malloc(5 * sizeof(dirent*));

    int i = 0;
    for (i = 0; i < directory_size; ++i){
        file_list[i] = (dirent*)malloc(50 * sizeof(dirent));
    }

    DIR *dir;
    struct dirent *sd;

    dir = opendir(".");

    if (dir == NULL){
        printf("Error! unable to open directory.\n");
        exit(1);
    }

    int count = 0;
    while ((sd = readdir(dir)) != NULL){
        file_list[count] = sd;
        printf("%s\n", file_list[count]->d_name);
        ++count;
    }

    size_t file_list_size = sizeof(&file_list) / sizeof(struct dirent);

    qsort(file_list, file_list_size, sizeof(struct dirent), sizeCompare);
}

我创建了一个简单的函数 sizeCompare 来表明我的函数正在运行,但我得到了空值。我的函数看起来像:

int sizeCompare(const void* a, const void* b){

    printf("%s\n", ((const struct dirent*)a)->d_name);
}

有人可以向我解释为什么我的 sizeCompare 没有正确检索数组值吗?

更新: 我试过调整 qsort 中的大小,结果我的值不再为空。下面一行给出了一个输出:

qsort(file_list, 1000, sizeof(struct dirent), sizeCompare);

显然 1000 不是一个好的解决方案。有人知道这样的数组的正确大小吗?

更新 2: sizeCompare函数只接受第一个参数,第二个参数为空

int sizeCompare(const void* a, const void* b){

    const struct dirent *first_dirent = *(const struct dirent **) a;
    const struct dirent *second_dirent = *(const struct dirent **) b;
    .......
    //first one works but second one is NULL
}

您的 sizeCompare 函数未返回任何内容。您需要实现的是 returns -1 当 a < b、0 当 a = b 和 1 当 a > b.

int sizeCompare(const void* a, const void* b) {
    // The implementation should return something
}

此外,您计算的 file_list_size 不正确。您不能将 count 作为第二个参数传递吗?

qsort(file_list, count, sizeof(struct dirent), sizeCompare);
  1. 在比较函数中,您需要通过首先转换为 struct dirent ** 来取消引用指针,就像这样

    const struct dirent *first_dirent = *(const struct dirent **) first_parameter;
    

    这是因为传递的是每个元素的地址,而元素是指针,所以传递给函数的指针是指向指针的指针。他们的void *地址是一样的,但是不能直接把const struct dirent **转成const struct dirent *.

  2. 你还有一个重要的问题,

    file_list_size = sizeof(&file_list) / sizeof(struct dirent);
    

    是错误的,尝试打印值看看应该是1

    file_list_size = count;
    

    因为您的代码计算指针的大小除以 struct dirent 的大小,这可能导致 0,请阅读 sizeof 运算符,其结果取决于通过的论点。当它是一个变量时,类型的大小就是结果,当变量是一个数组时,它就是数组的大小。

    由于file_list是指向指针的指针,即不是数组,那么

    的结果
    file_list_size = sizeof(&file_list) / sizeof(struct dirent);
    

    不是你想的那样,也不是你想的那样。

  3. 没有正确的大小,也许您应该先计算条目数并预测代码中第一个 malloc() 的值。或使用realloc()并动态计算条目并同时分配指针。

还有:

  • 正如@user3629249 in

  • 所指出的那样,您的代码泄漏了内存
  • 你不需要cast the return value from malloc()

  • 尽量不要将代码与声明混在一起,这样很难跟踪变量及其作用域。

  • 您为 5 个 struct dirent * 指针分配了 space,但您从不检查计数变量是否达到或超过该值。这可能会导致未定义的行为。

  • 您的代码也会泄漏内存,因为您从不调用 closedir().

这是一个按字母顺序排列条目的示例

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

#include <dirent.h>

int
compareSize(const void *const A, const void *const B)
{
    return strcmp((*(struct dirent **) A)->d_name, (*(struct dirent **) B)->d_name);
}

void printSortedNames(const char *const path)
{
    int count;
    DIR *dir;
    struct dirent **list;
    struct dirent *entry;

    dir = opendir(path);
    if (dir == NULL)
    {
        fprintf(stderr, "cannot open `%s'\n", path);
        return;
    }

    /* First determine the number of entries */
    count = 0;
    while ((entry = readdir(dir)) != NULL)
        ++count;
    /* Allocate enough space */
    list = malloc(count * sizeof(*list));
    if (list == NULL)
    {
        closedir(dir);
        fprintf(stderr, "memory exhausted.\n");
        return;
    }
    /* You don't need to allocate the list elements
     * you can just store pointers to them in the
     * pointer array `list'
     */
    rewinddir(dir); /* reset position */
    /* Save the pointers allocated by `opendir()' */
    count = 0;
    while ((entry = readdir(dir)) != NULL)
        list[count++] = entry;
    /* Call `qsort()', read about the `sizeof' operator */
    qsort(list, count, sizeof(*list), compareSize);
    /* Print the sorted entries now */
    for (int index = 0 ; index < count ; ++index)
        fprintf(stderr, "%s\n", list[index]->d_name);
    closedir(dir);
}

int
main(void)
{
    printSortedNames("/home/iharob");
    return 0;
}

1记得将count的值限制为你分配的最大指针数space对于.