带有字母数字文件名的 qsort 动态二维字符数组 - C 程序

qsort dynamic 2d char array with alphanumeric filenames - C program

我是新来的,所以这是我的第一个 post。我一直在努力解决这个问题 2 周。我试图打开一个目录,捕获并存储找到的文件的名称,按升序对它们进行排序,然后打印结果。我的问题是 qsort 导致我的程序完全崩溃,或者 qsort 根本不对数组进行排序,因为文件是字母数字。我什至尝试循环遍历存储的文件名以输出每个字符,只是为了看看我是否最终可以尝试比较两个数组位置之间的字符以进行排序。但我注意到它似乎无法看到或识别字母数字文件名中的数字(例如:"f1.jpg" 只会打印 "f",一个空白,然后是 "j",就是这样。我应该注意,我不能更改文件名,因为我事先不知道名称或文件总数。我试图使它成为动态的。以下是我遇到问题的主要代码,因为它在 'qsort' 关键字处崩溃:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <conio.h>
#include <ctype.h>
#include <time.h>
#include <dirent.h>
#include <math.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int compare(const void *a, const void *b);
void readInFilenames();

int main
{
   readInFilenames();
   system("pause");
}

int compare(const void *a, const void *b)
{
  return strcmp(*(char **)a, *(char **)b);
}

void readInFilenames()
{
  char cwd[1024];
  DIR *dir = NULL;
  struct dirent *pent = NULL;
  struct stat info;
  char file_path[50] = "files/";
  int total_files = 0;
  int file_size;

  // Change directory to file location
  chdir(file_path);

  if((getcwd(cwd, sizeof(cwd))) != NULL)
  {
    printf("Current Directory: %s\n", cwd);
  }

  // Open directory and count the total number of files found
  dir = opendir(cwd);

  if(dir != NULL)
  {
    while((pent = readdir(dir)) != NULL)
    {
        if(stat(pent->d_name, &info))
        {
            printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
        }
        else
        {
            if(S_ISREG(info.st_mode))
            {
                if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
                {
                    continue;
                }
                else
                {
                    total_files++;
                    file_size = sizeof(pent->d_name);
                }
            }
        }
    }
    printf("# of files found: %d\n", total_files);
    rewinddir(dir);    //reset pointer back to beginning of file directory

    // Create character array to store file names;
    char *filenames_arr[total_files][file_size];
    int size = sizeof(filenames_arr)/sizeof(filenames_arr[total_files]);

    total_files = 0;   //reset file counter back to 0;

    // Read and store file names in the character array
    while((pent = readdir(dir)) != NULL)
    {
        if(stat(pent->d_name, &info))
        {
            printf("ERROR: stat%s: %s\n", pent->d_name, strerror(errno));
        }
        else
        {
            if(S_ISREG(info.st_mode))
            {
                if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
                {
                    continue;
                }
                else
                {
                    strcpy(filenames_arr[total_files], pent->d_name);
                    //printf("%s\n", filenames_arr[i]);
                    total_files++;
                }
            }
        }
    }
    closedir(dir);

    // Print original array contents
    printf("Original List of Files\n");
    printf("----------------------\n");
    for(int i = 0; i < total_files; i++)
    {
      printf("%s\n", filenames_arr[i]);
    }

    // Sort array in ascending order
    qsort(filenames_arr, total_files, size, compare);
    //qsort(filenames_arr, total_files, sizeof(filenames_arr[0]), (char (*)(const void*, const void*))strcmp);

    // Print organized array contents
    printf("Sorted List of Files\n");
    printf("----------------------\n");
    for(int i = 0; i < total_files; i++)
    {
      printf("%s\n", filenames_arr[i]);
    }
    printf("\nFinished!\n");
  }
}

这部分代码是在我尝试打印每个单独的字符时使用的。这最初位于前面代码中最终数组打印发生的位置:

    int i = 0;
    int j = 0;
    while(i < total_files)
    {
        printf("File Name: %s\n", filenames_arr[i]);
        printf("String Length: %d\n", strlen(filenames_arr[i]));
        while(filenames_arr[i] != '[=11=]')
        {
            printf("Checking filenames_arr[%d][%d]\n", i, j);

            if(isalpha((unsigned char)filenames_arr[i][j]) != 0)
            {
                printf("In isalpha\n");
                printf("Found: %c\n", filenames_arr[i][j]);
            }
            else if(isdigit((unsigned char)filenames_arr[i][j]) != 0)
            {
                printf("In isdigit\n");
                printf("Found: %d\n", filenames_arr[i][j]);
            }
            j++;
        }
        printf("-------------------------------------------\n");
        i++;
        j = 0;
    }

如何使用 qsort 对二维字母数字字符串数组进行排序?导致我的程序崩溃的 qsort 或什至是我的数组设置有什么问题?另外,qsort 是如何工作的?我曾尝试搜索论坛和在线课程笔记,以了解 qsort 是否仅通过查看第一个字符、所有字符或数字是否有问题来进行排序。提前致谢!

更新:

我对我的代码进行了以下修改。它工作得更好,因为 qsort 不再使程序崩溃。但是,qsort 仍然没有排序。以下是我所做的更新,以及结果的屏幕截图:

typedef struct{
  char *filename;
}filedata;

int compare(const void *a, const void *b);
void readInFilenames();

int main(void){
  readInFilenames();
  system("pause");
}

int compare (const void *a, const void *b ) {
  filedata *ia = (filedata *)a;
  filedata *ib = (filedata *)b;
  return strcmp(ia->filename, ib->filename);
}

readInFilenames(){
.
.
.
  printf("# of files found: %d\n", total_files);
  rewinddir(dir);

  filedata fn_data[total_files];
  total_files = 0;

  printf("Original Array: \n");
  while((pent = readdir(dir)) != NULL)
  {
    .
    .
    .
    if((strcmp(pent->d_name, ".cproject") == 0) || (strcmp(pent->d_name, ".project") == 0))
    {
        continue;
    }
    else
    {
        fn_data[total_files].filename = malloc(file_size + 1);
        strcpy(fn_data[total_files].filename, pent->d_name);
        printf("%s\n", fn_data[total_files].filename);
        total_files++;
    }
  }
  closedir(dir);

  printf("\n");
  qsort(fn_data, total_files, sizeof(filedata), compare);

  printf("Sorted Array:\n");
  for(int i = 0; i < total_files; i++)
    printf("%s\n", fn_data[i].filename);

  printf("Finished!\n");
}

Click here to see sorting results

列表应打印:f0.dat、f1.dat、f2.dat、f3.dat、...、f20.dat。但它会打印:f0.dat、f1.dat、f10.dat、f11.dat、...、f9.dat.

OP 已修复代码以通过启用警告和使用 建议来应对 "qsort dynamic 2d char array with filenames"。

然而,代码仍在与 strcmp() 进行比较,后者仅将数字视为字符,而不是数字来实现 f1.dat, f2.dat, f3.dat,...,f20.dat 顺序。


以下是一个比较函数,它查找数字以调用数字 sub-strings 的替代比较。 OP 可以根据详细的编码目标对此比较进行修改。

int AdamsOrder(const char *s1, const char *s2) {
  // Compare as `unsigned char` as that is `strcmp()` behavior.  C11 7.24.1 3
  const unsigned char *us1 = (const unsigned char *) s1;
  const unsigned char *us2 = (const unsigned char *) s2;
  while (*us1 && *us2) {
    if (isdigit(*us1) && isdigit(*us2)) {
      char *end;  // dummy
      unsigned long long l1 = strtoull(us1, &end, 10);  // Parse for a number
      unsigned long long l2 = strtoull(us2, &end, 10);
      if (l1 > l2) return 1;
      if (l1 < l2) return -1;
      // Continue on treating as text. OP needs to decide how to handle ties: "0001" vs "1"
    }
    if (*us1 > *us2) return 1;
    if (*us1 < *us2) return -1;
    us1++;
    us2++;
  }
  // At this point, at least one string ended (i.e. points to '[=10=]').
  // The return statement below will behave as follows:
  // If a string ended, *us1/2 will be 0. Let an unfinished one be X > 0.
  // First string ended : ( 0 > X ) - ( 0 < X ) = false - true  = 0 - 1 = -1
  // Second string ended: ( X > 0 ) - ( X < 0 ) = true  - false = 1 - 0 =  1
  // Both strings ended : ( 0 > 0 ) - ( 0 < 0 ) = false - false = 0 - 0 =  0      
  return (*us1 > *us2) - (*us1 < *us2);
}