简体   繁体   中英

Qsort not displaying in correct order

I use qsort to sort my array of ProcEntry pointers and am trying to get them to be sorted in ascending order but for some reason only a couple of the pointers are out of place. I've tried multiple types of comparators for my defaultSort function but cannot seem to figure out why some values are not being sorted. ''' /* * Author: Kaden Baratcart * Date: Mon 08 Aug 2022 09:17:37 PM MST * Description: Starter code for final project (myps) */

#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;
}

You ask qsort() to sort a namelist ( struct dirent ** ). It's odd that you say the size of each element is sizeof(ProcEntry *) instead of sizeof(*namelist) but I guess that's ok as pointers are the same size. Your sort function, however, is passed two struct dirent ** , and while you have not told us what ProcEntry is, the cast *(ProcEntry **) is almost certainly incorrect.

This sorts the result by name ( d_name ) with a separate qsort() :

#define _POSIX_C_SOURCE 200809L
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int dirent_cmp(const void *a, const void *b) {
    return strcmp(
        (*(struct dirent **) a)->d_name,
        (*(struct dirent **) b)->d_name
    );
}

int main (int argc, char * argv[]) {
    struct dirent **namelist;
    int n = scandir(".", &namelist, NULL, NULL);
    qsort(namelist, n, sizeof(*namelist), dirent_cmp);
    for(int i = 0; i < n; i++) {
        printf("%s\n", namelist[i]->d_name);
    }
}

As noted scandir() will sort the result for you internally if you specify a compare function as the 4th argument (renamed the compare function to dirent_cmp2() to highlight that the declaration uses different types of a and b ):

#define _POSIX_C_SOURCE 200809L
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int dirent_cmp2(const struct dirent **a, const struct dirent **b) {
    return strcmp((*a)->d_name, (*b)->d_name);
}

int main (int argc, char * argv[]) {
    struct dirent **namelist;
    int n = scandir(".", &namelist, NULL, dirent_cmp2);
    for(int i = 0; i < n; i++) {
        printf("%s\n", namelist[i]->d_name);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM