0

I am trying to recreate the Linux command ls in C. I have the program working (going through a list of directories passed in as command line arguments, and pushing all the contents to an array of strings).

Now I'm trying to implement the quicksort flag for the command (e.g. ls -s /dev), which should print out all the contents in a lexicographical order. The problem is that the qsort() method in stdlib.h only "sorts" one element (basically swaps the first and the last element in the array) for my program.

I have no idea what's wrong, as all my pointers are properly set up as well. I'm adding the relevant snippet codes below, please let me know if something catches your eye that has been escaping mine for two days.

Compare function for qsort:

int normalCompare (const void *stringOne, const void *stringTwo) {
   return strcmp((const char *)stringOne, (const char *)stringTwo);
}  

Actual function call:

void execute_ls(char **directoryList, Flags flags) {

   //Create a buffer for directories' file names
   char **fileNamesList;
   fileNamesList = malloc(MAX_FILES * sizeof (*fileNamesList));
   int fileBufferCurrentPointer = 0;

   //Fill the buffer out by calling execute_ls_one_dir on all the directories
   int i = 0;
   while(directoryList[i] != NULL) {
      execute_ls_one_dir(directoryList[i], fileNamesList, &fileBufferCurrentPointer);
      i++;
   }
   fileNamesList[fileBufferCurrentPointer] = NULL;

   //Process the array
   if(flags.s == 1) {
       qsort(fileNamesList, fileBufferCurrentPointer, sizeof (char *), normalCompare);
   }
   else if(flags.r == 1) {
       qsort(fileNamesList, fileBufferCurrentPointer, sizeof (char *), reverseCompare);
   }

   //Print to user
   for(i = 0; i < fileBufferCurrentPointer; i++) {
       if(((*fileNamesList[i] == '.') && (flags.a == 1)) || (*fileNamesList[i] != '.')) {
        printf("%s\n", fileNamesList[i]);
       }
   }

   //Deallocate fileNamesList
   for(i = 0; i < MAX_FILES; i++) {
       free(fileNamesList[i]);
   }
   free(fileNamesList);
}  

Updating the fileBufferCurrentPointer:

while((oneDirEntryPtr = readdir(currentDirPtr)) != NULL) {

    // Push the file name onto the fileNamesList array
    fileNamesList[*fileBufferCurrentPointer] = malloc(MAX_LEN_NAME * sizeof (char));
    strcpy(fileNamesList[*fileBufferCurrentPointer], oneDirEntryPtr->d_name);
    *fileBufferCurrentPointer += 1;
}  

I'm confused as to why qsort is only working once (technically isn't even passing through the array once instead of recursively multiple times to complete the algorithm).

ScaVenGerS
  • 61
  • 1
  • 10
  • This is a duplicate question. It will be modestly hard to find the question(s) of which it is a duplicate. – Jonathan Leffler Mar 29 '17 at 16:49
  • @JonathanLeffler It almost works now after some tweaking, but some of the elements are displaced at the beginning, everything else in the array is properly sorted. – ScaVenGerS Mar 29 '17 at 16:52
  • It's probably not going to be possible to you more help without an MCVE ([MCVE]). I think you should accept the current answer which correctly diagnoses one of your problems. Then create an MCVE to ask a new question. We'll need the sample input data, the output you get, and the output you expect. Your code will be relatively small. It probably shouldn't even read a directory — it can use a built-in shuffled list of names to be sorted. Of course, that might not reproduce your problem, but then it gives you clues about where to look. The MCVE _must_ reproduce the problem. – Jonathan Leffler Mar 29 '17 at 17:00

1 Answers1

2

you've made a common mistake in thinking the comparison function is taking two elements from your array - it's actually taking two pointers to elements in your array so you should call strcmp like this

int normalCompare (const void *stringOne, const void *stringTwo) {
   return strcmp(*(const char **)stringOne, *(const char **)stringTwo);
}
Chris Turner
  • 8,082
  • 1
  • 14
  • 18
  • That makes sense! But it's almost working now, some of the first few filenames are jumbled up but it randomly works after 4-5 file names properly. – ScaVenGerS Mar 29 '17 at 16:44
  • you're also freeing too much - your loop goes up to MAX_FILES, but it should stop at fileBufferCurrentPointer. This is likely to cause all kinds of memory issues which might explain the oddness you're seeing – Chris Turner Mar 29 '17 at 16:49
  • I just saw that, thank you for the heads up! Doesn't help with the results though. – ScaVenGerS Mar 29 '17 at 16:50