You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

qsort排序ProcEntry指针数组顺序异常问题求助

问题分析与解决

我尝试用qsort对ProcEntry指针数组进行升序排序,但部分指针位置不符合预期,试了多种defaultSort比较器实现都没解决问题,相关代码如下:

#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <dirent.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <ctype.h>

#include "ProcEntry.h"

#define MAX_PATH_LENGTH 4096

#define UNUSED(x) (void)x

static int defaultFilter(const struct dirent *current){
    return isdigit(current->d_name[0]);
}
static int defaultSort(const void * procEntryPtr1, const void * procEntryPtr2){
    /* Dereference the parameters to access the ProcEntry pointers */
    ProcEntry *ProcEntry1 = *(ProcEntry **)procEntryPtr1; 
    ProcEntry *ProcEntry2 = *(ProcEntry **)procEntryPtr2;

    // if((ProcEntry1)->pid < (ProcEntry2)->pid) return -1;
    // if((ProcEntry1)->pid == (ProcEntry2)->pid) return 0;
    // if((ProcEntry1)->pid > (ProcEntry2)->pid) return 1;
   
    return (ProcEntry2->pid > ProcEntry1->pid) - (ProcEntry2->pid < ProcEntry1->pid);
    //return ProcEntry1 < ProcEntry2 ? -1 : ProcEntry1 > ProcEntry2 ? 1 : 0;
}

int main (int argc, char * argv[]) {

    struct dirent **namelist;
    int n;
    int opt;
    int print = 0; // 0 for no 1 for yes

    /* Declare filterFunction pointer */
    int(*filterFunction)(const struct dirent *);
    filterFunction = defaultFilter;
    /* Declare filterFunction pointer */
    int(*sortFunction)(const void *, const void *);
    sortFunction = defaultSort;
    char* dir = "/proc";

    /* Variable Fields */

    while((opt = getopt(argc, argv, "d:pczh")) != -1){
        switch(opt){
            case 'd':
                dir = argv[2];
                if(strcmp(dir, "/proc") == 0){
                    filterFunction = defaultFilter;
                } else {
                    filterFunction = NULL;
                }
                print = 1;
                break;
            case 'p':   //Part 3
                print = 1;
                filterFunction = defaultFilter;
                sortFunction = defaultSort;
                break;
            case 'c':   //Part 3
                break;
            case 'z':   //Part 3
                break;
            case 'h':
                print = 0;
                printf("Usage: %s [-d <path>] [-p] [-c] [-z] [-h]\n", argv[0]);
                printf("\t-d <path> Directory containing proc entries (default: /proc)\n");
                printf("\t-p        Display proc entries sorted by pid (default)\n");
                printf("\t-c        Display proc entries sorted by command lexicographically\n");
                printf("\t-z        Display ONLY proc entries in the zombie state \n");
                printf("\t-h        Display this help message\n");
                break;
            default:
                fprintf(stderr,"Error: Invalid Option Specified\n");
                fprintf(stderr, "Usage: %s [-d <path>] [-p] [-c] [-z] [-h]\n", argv[0]);
                printf("\t-d <path> Directory containing proc entries (default: /proc)\n");
                printf("\t-p        Display proc entries sorted by pid (default)\n");
                printf("\t-c        Display proc entries sorted by command lexicographically\n");
                printf("\t-z        Display ONLY proc entries in the zombie state \n");
                printf("\t-h        Display this help message\n");
        }
    }
    if(argc > 6){
        fprintf(stderr, "Usage: ./myps [-d <path>] [-p] [-c] [-z] [-h]\n");
        printf("\t-d <path> Directory containing proc entries (default: /proc)\n");
        printf("\t-p        Display proc entries sorted by pid (default)\n");
        printf("\t-c        Display proc entries sorted by command lexicographically\n");
        printf("\t-z        Display ONLY proc entries in the zombie state \n");
        printf("\t-h        Display this help message\n");
    }

    n = scandir(dir, &namelist, filterFunction, alphasort);
    qsort(namelist, n, sizeof(ProcEntry *), sortFunction);
    if (n < 0)
        perror("scandir");
    else {
        while (n--) {
            printf("%s\n", namelist[n]->d_name);
            free(namelist[n]);
        }
        free(namelist);
    }

    /* display the names on stdout stream */
    if(print == 1){
        print = 0;
        int i;
        for (i = 0; i < n; ++i) {
            fprintf(stdout,"%s\n", namelist[i]->d_name);
        }
    }
        
    return 0;
}

核心错误点

  1. 类型完全不匹配:

    • scandir返回的namelist是struct dirent **类型数组,每个元素是指向struct dirent的指针,但defaultSort函数却把这些指针强制转换成ProcEntry **并访问pid成员,属于非法内存访问,行为完全未定义,必然导致排序异常或程序崩溃。
    • qsort的第三个参数错误:应传入sizeof(struct dirent *),而非sizeof(ProcEntry *),否则qsort计算元素偏移时会出错。
  2. 排序逻辑前提错误:
    尚未将struct dirent转换为ProcEntry就直接排序,namelist中根本不存在ProcEntry对象。若要按PID排序,要么直接在排序函数里解析d_name(/proc下的目录名即PID字符串)为整数比较,要么先生成ProcEntry数组再排序。

  3. 打印逻辑错误:
    在第一个while(n--)循环中,n已被递减至0,后续for循环的i < n条件永远不成立,不会执行任何打印。

修正方案

方案1:直接基于struct dirent按PID排序

修改defaultSort和qsort调用:

static int defaultSort(const void *a, const void *b) {
    // a和b是struct dirent*的指针
    const struct dirent *dirent1 = *(const struct dirent **)a;
    const struct dirent *dirent2 = *(const struct dirent **)b;
    
    // 将目录名(PID字符串)转换成整数
    pid_t pid1 = atoi(dirent1->d_name);
    pid_t pid2 = atoi(dirent2->d_name);
    
    // 升序排序:pid1 < pid2返回-1,相等返回0,否则返回1
    if (pid1 < pid2) return -1;
    if (pid1 > pid2) return 1;
    return 0;
}

// 在main里修改qsort调用:
qsort(namelist, n, sizeof(struct dirent *), defaultSort);

方案2:先构建ProcEntry数组再排序

若确实需要使用ProcEntry,需先遍历namelist创建ProcEntry对象,再对数组排序:

// 假设ProcEntry结构体包含pid字段,且有创建/释放函数
int main() {
    // ... 其他代码 ...
    n = scandir(dir, &namelist, filterFunction, alphasort);
    if (n < 0) {
        perror("scandir");
        return 1;
    }

    // 分配ProcEntry指针数组
    ProcEntry **procEntries = malloc(n * sizeof(ProcEntry *));
    if (!procEntries) {
        perror("malloc");
        while (n--) free(namelist[n]);
        free(namelist);
        return 1;
    }

    // 填充ProcEntry数组
    for (int i = 0; i < n; i++) {
        pid_t pid = atoi(namelist[i]->d_name);
        procEntries[i] = createProcEntry(pid); // 假设存在该创建函数
        free(namelist[i]);
    }
    free(namelist);

    // 排序ProcEntry数组
    qsort(procEntries, n, sizeof(ProcEntry *), defaultSort);

    // 打印并释放资源
    for (int i = 0; i < n; i++) {
        printf("%d\n", procEntries[i]->pid);
        freeProcEntry(procEntries[i]); // 假设存在该释放函数
    }
    free(procEntries);

    // ... 其他代码 ...
}

修正打印逻辑

若保留原打印逻辑,需先保存n的初始值,且注意不能访问已释放的namelist:

int original_n = n;
// 先处理打印再释放资源
if(print == 1){
    for (int i = 0; i < original_n; ++i) {
        fprintf(stdout,"%s\n", namelist[i]->d_name);
    }
}
// 再释放namelist
while (original_n--) {
    free(namelist[original_n]);
}
free(namelist);

内容的提问来源于stack exchange,提问作者Kaden Baratcart

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 11:09:27