如何使用qsort根据字节对包含路径名/文件的char进行排序?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用qsort根据字节对包含路径名/文件的char进行排序?相关的知识,希望对你有一定的参考价值。

我基本上编写了一个代码,其中我接受两个命令行参数,一个是我想要在我的目录中搜索的文件类型,另一个是我想要的数量(尚未实现,但我可以修复)代码是这样的:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define sizeFileName 500
#define filesMax 5000

int cmpfunc( const void *a, const void *b) {
  return *(char*)a + *(char*)b;
}

int main( int argc, char ** argv) {
  FILE * fp = popen( "find . -type f", "r");
  char * type = argv[1];
  char * extension = ".";

  char* tExtension;
  tExtension = malloc(strlen(type)+1+4);
  strcpy(tExtension, extension);
  strcat(tExtension, type);
  // printf("%s
",tExtension);

  int amount = atoi(argv[2]);
  //printf("%d
",amount);

  char buff[sizeFileName];
  int nFiles = 0;
  char * files[filesMax];
  while(fgets(buff,sizeFileName,fp)) {
    int leng = strlen(buff) - 1;
    if (strncmp(buff + leng - 4, tExtension, 4) == 0){
      files[nFiles] = strndup(buff,leng);
      //printf("	%s
", files[nFiles]);
      nFiles ++;
    }
  }
  fclose(fp);
  printf("Found %d files
", nFiles);

  long long totalBytes = 0;
  struct stat st;

  // sorting based on byte size from greatest to least
  qsort(files, (size_t) strlen(files), (size_t) sizeof(char), cmpfunc);

  for(int i = 0;i< nFiles; i ++) {
    if(0!= stat(files[i],&st)){
      perror("stat failed:");
      exit(-1);
    }
    totalBytes += st.st_size;
    printf("%s : %ld
",files[i],st.st_size);
  }
  printf("Total size: %lld
", totalBytes);
  // clean up
  for(int i = 0; i < nFiles ; i ++ ) {
    free(files[i]);
 }
  return 0;
}

到目前为止,我已经正确设置了每个部分,在运行代码时说$./find ini 5,它将打印出所有ini files,然后是字节大小(它当前忽略了5)。然而,对于qsort(),我不确定如何排序char * files的内容,因为它保存路径名,我不得不使用stat来获取字节大小,我将如何打印出我的打印语句的排序版本第一个语句是最多字节,最少字节完成?

答案

如果我们假设您的输入有效,您的问题可以通过以下方式简化:

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

#define filesMax 5000

int cmpfunc(const void const *a, const void *b) { return *(char *)a + *(char *)b; }

int main(void) {
  int nFiles = 4;
  char *files[filesMax] = {"amazing", "hello", "this is a file", "I'm a bad file"};
  qsort(files, strlen(files), sizeof(char), cmpfunc);

  for (int i = 0; i < nFiles;; i++) {
    printf("%s
", files[i]);
  }
}

如果您使用警告进行编译,则可以:

source_file.c:11:23: warning: incompatible pointer types passing 'char *[5000]' to parameter of type 'const char *' [-Wincompatible-pointer-types]
  qsort(files, strlen(files), sizeof(char), cmpfunc);
                      ^~~~~

qsort()期望你的数组的大小(或者在你的情况下是一个子类),它也期望你的数组的一个元素的大小。你错误地把它给了它。此外,您的比较函数不会比较任何东西,您当前正在添加char的两个指针的第一个字节,这没有多大意义。

要修复您的代码,您必须写:

qsort(files, nFiles, sizeof *files, &cmpfunc);

并修复比较功能:

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

int cmpfunc(void const *a, void const *b) { return cmpfunc_aux(a, b); }

也应该是size_t类型的大小:

size_t nFiles = 0;

不要忘记有关如何使用函数的所有信息都写在他们的doc中。


我将如何打印出我的打印语句的排序版本,其中第一个语句是最多字节并以最少字节结束?

您的代码没有显示您尝试这样做的任何线索,您当前正在存储名称文件而且只存储该文件。您如何期望使用未获得的信息对文件进行排序?

但是,简单地创建一个包含文件名和大小的结构,获取对其进行排序和排序所需的信息:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <inttypes.h>

struct file {
  off_t size;
  char *name;
};

int cmpfunc_aux(struct file const *a, struct file const *b) {
  if (a->size > b->size) {
    return -1;
  } else if (a->size < b->size) {
    return 1;
  } else {
    return 0;
  }
}

int cmpfunc(void const *a, void const *b) { return cmpfunc_aux(a, b); }

#define filesMax 5000

int main(void) {
  size_t nFiles = 4;
  struct file files[filesMax] = {{42, "amazing"},
                                 {21, "hello"},
                                 {168, "this is a file"},
                                 {84, "I'm a bad file"}};
  qsort(files, nFiles, sizeof *files, &cmpfunc);

  for (size_t i = 0; i < nFiles; i++) {
    printf("%s, %" PRId64 "
", files[i].name, (intmax_t)files[i].size);
  }
}
另一答案

函数cmpfunc()提供了每个字符串的第一个字符,并且这不是一个正确的比较函数(当你切换参数时它应该给出一个相反的符号值,例如,如果"a""b"是要比较的字符串,它会添加前两个字符两个字符串,给97+98 == 195,在unsigned chars上是积极的,然后用"b""a"调用应该给出一个负数(并且它再次给你98 + 97 == 195),更多的是,它总是给出相同的结果---即使用signed chars-- - 所以它不能用作排序比较器)

在比较字符串时,为什么不使用标准库函数strcmp(3)这是一个有效的比较函数?如果第一个字符串在字典上比第二个字符串更少,则给出负数,如果两者相等则为0,如果第一个字符串在字典上比第二个字符串更大,则给出正数。

如果您的函数必须按文件名的长度检查(和排序),那么您可以将其定义为:

int cmpfunc(char *a, char *b) /* yes, you can define parameters as char * */
{
    return strlen(a) - strlen(b);
}

或者,首先根据文件长度,然后按字典顺序:

int cmpfunc(char *a, char *b)
{
    int la = strlen(a), lb = strlen(b);
    if (la != lb) return la - lb;
    /* la == lb, so we must check lexicographycally */
    return strcmp(a, b);
}

现在,为了继续帮助你,我需要知道为什么你需要对任何东西进行排序,就像你说你想在目录中搜索文件一样,问题在哪里进行排序?

以上是关于如何使用qsort根据字节对包含路径名/文件的char进行排序?的主要内容,如果未能解决你的问题,请参考以下文章

对结构中的多个项目进行 qsort

qsort

qsort()函数(C)

如何将长双打与 qsort 以及关于 NaN 进行比较?

使用 qSort 对字符串进行排序

4.19 使用qsort对结构体数组进行排序,实现对结构的体一级排序和二级排序,进一步了解qsort的原理