首页 > 解决方案 > 我在递归函数中声明了一个数组。我该如何排序?

问题描述

我在递归函数中声明了一个数组。是否可以在输出之前对其进行排序?我从另一个递归函数得到的大小。

void listFilesRecursively(char *basePath, int size) {
    char path[1000];
    struct dirent *dp;
    struct file files[size];
    struct stat buf;
    DIR *dir = opendir(basePath);
    int counter = 0;
    if (!dir) return;
    while ((dp = readdir(dir)) != NULL) {
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
            strcpy(path, basePath);
            strcat(path, "/");
            strcat(path, dp->d_name);
            files[counter].name = path;
            stat(path, &buf);
            files[counter].file_info.st_size = buf.st_size;
            printf("%s%s%ld%s\n", files[counter].name, " - ",
                   files[counter].file_info.st_size, "bytes");
            counter++;

            listFilesRecursively(path, size);
        }
    }
    closedir(dir);
}

标签: crecursiondirectory

解决方案


警告:files[counter].name=path保存一个局部变量地址,并在每个循环中修改它,因此所有名称都相同,您需要保存它的副本(strdup

对于listFilesRecursively的每次调用,您在堆栈中使用超过 1000 个字节,最好不要在堆栈中使用该字符串并直接使用在堆中分配的路径

我没有看到将文件计数器作为局部变量的兴趣,您将它们释放出去

提案

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

#define NFILES 100;

typedef struct file  {
  char * name;
  struct stat file_info;
} file;

void listFilesRecursively(char *basePath, file ** files, int * size, int * index) 
{
  DIR *dir = opendir(basePath);

  if (!dir) 
    return;

  struct dirent *dp;
  struct stat buf;

  while ((dp = readdir(dir)) != NULL)
  {
    if ((strcmp(dp->d_name, ".") != 0) && (strcmp(dp->d_name, "..") != 0))
    {
        size_t sz = strlen(basePath);

        char * pathname = malloc(sz + strlen(dp->d_name) + 2);

        if (pathname == NULL) {
          /* out of memory */
          closedir(dir);
          return;
        }

        strcpy(pathname, basePath);
        pathname[sz] = '/';
        strcpy(pathname + sz + 1, dp->d_name);

        stat(pathname, &buf);

        if (S_ISDIR(buf.st_mode)) {
          /* suppose dirs not memorized */
          listFilesRecursively(pathname, files, size, index);
          free(pathname);
        }
        else if (S_ISREG(buf.st_mode)) {
          /* a file, memorize it */
          if (++*index == *size) {
            *size += NFILES;
            *files = realloc(*files, (*size) * sizeof(file));
          }

          (*files)[*index].file_info = buf;
          (*files)[*index].name = pathname;
        }
        else
          /* bypassed */
          free(pathname);
    }
  }

  closedir(dir);
}

int compPathname(const void * a, const void * b)
{
  return strcmp(((file *) a)->name, ((file *) b)->name);
}

int main()
{
  int size = NFILES;
  int index = -1;
  file * files = malloc(size * sizeof(file));

  listFilesRecursively(".", &files, &size, &index);

  if (index != -1) {
    qsort(files, index + 1, sizeof(file), compPathname);

    /* write and free memory */
    for (int i = 0; i <= index; ++i) {
      printf("%s : %ld\n", files[i].name, (long) files[i].file_info.st_size);
      free(files[i].name);
    }
  }

  free(files);

  return 0;
}

我只记住常规文件的路径名和大小,不保存目录和动态链接等

我按路径名排序

每次文件太小我都会添加 NFILES,NFILES 可以是任何数字 > 0


在 valgrind 下执行:

==9329== Memcheck, a memory error detector
==9329== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9329== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==9329== Command: ./a.out
==9329== 
./.X0-lock : 11
./a.out : 12920
./f.c : 2485
./vgdb-pipe-shared-mem-vgdb-9329-by-pi-on-??? : 36
==9329== 
==9329== HEAP SUMMARY:
==9329==     in use at exit: 0 bytes in 0 blocks
==9329==   total heap usage: 35 allocs, 35 frees, 339,242 bytes allocated
==9329== 
==9329== All heap blocks were freed -- no leaks are possible
==9329== 
==9329== For counts of detected and suppressed errors, rerun with: -v
==9329== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)

推荐阅读