我有一个在递归函数中声明的数组。如何分类?

时间:2019-01-20 10:41:01

标签: c recursion directory

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

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

2 个答案:

答案 0 :(得分:1)

警告: require 'dompdf/autoload.inc.php'; $html = empty( $html ) ? $this->get_order_pdf_html( $order_id, 'pdf' ) : $html; $dompdf = new Dompdf( array( 'isRemoteEnabled' => true, ) ); $dompdf->setPaper( 'A4', 'portrait' ); $dompdf->set_option('isHtml5ParserEnabled', true); $dompdf->loadHtml( $html, 'UTF-8' ); $dompdf->render(); $output = $dompdf->output(); if( $save_pdf ) { $invoice_file_name = sprintf( '%s/uploads/document-%s-%s.pdf', WP_CONTENT_DIR, $order_id, time("H:s") ); file_put_contents( $invoice_file_name, $output); return $invoice_file_name; } if( $download_pdf ) { $dompdf->stream( sprintf( "%s-%s", __('document'), $order_id ) ); return true; } return $output; } 保存一个本地变量地址,并在每次循环时对其进行修改,因此所有名称都相同,您需要保存一个副本( strdup

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

我不希望将文件计数器作为局部变量,而将它们放出去

提案

files[counter].name=path

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

我按路径名排序

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


在valgrind下执行:

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

答案 1 :(得分:0)

您的方法无效:

  • 在每个递归级别上都有一个新的数组files定义。
  • 为数组中每个条目保存的路径都是相同的,这是指向函数中定义的本地数组path的指针。

使files成为全局变量是可能的,但是应避免使用全局变量。相反,应在递归下降过程中找到更多条目时,向指针传递递归函数外部定义的结构,并在此结构内重新分配数组。每个文件的路径副本应使用strdup分配。为了限制堆栈空间要求,path也可以是此结构的一部分,并将目录部分的长度传递给递归函数。

这是修改后的版本:

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

struct file {
    char *name;
    struct {
        long st_size;
    } file_info;
};

typedef struct dir_state {
    char path[1024];
    struct file *files;
    int files_size;
    int files_count;
} dir_state;

int listFilesRecursively(dir_state *sp) {
    struct dirent *dp;
    struct stat buf;
    int counter = 0;
    int path_len = strlen(sp->path);
    DIR *dir = opendir(sp->path);
    if (!dir)
        return 0;
    while ((dp = readdir(dir)) != NULL) {
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0) {
            snprintf(sp->path + path_len, sizeof(sp->path) - path_len, "/%s", dp->d_name);
            if (sp->files_count == sp->files_size) {
                int new_size = sp->files_size * 3 / 2 + 16;
                struct file *new_p = realloc(sp->files, new_size * sizeof(*new_p));
                if (new_p == NULL)
                    return -1;
                sp->files_size = new_size;
                sp->files = new_p;
            }
            memset(&sp->files[sp->files_count], 0, sizeof(struct file));
            sp->files[sp->files_count].name = strdup(sp->path);
            if (!stat(sp->path, &buf))
                sp->files[sp->files_count].file_info.st_size = buf.st_size;
            printf("%s%s%ld%s\n", sp->files[sp->files_count].name, " - ",
                   sp->files[sp->files_count].file_info.st_size, "bytes");
            sp->files_count++;
            counter++;
            listFilesRecursively(sp);
        }
    }
    closedir(dir);
    sp->path[path_len] = '\0';
    return counter;
}

int cmp_name(const void *a, const void *b) {
    const struct file *aa = a;
    const struct file *bb = b;
    return strcmp(aa->name, bb->name);
}

int cmp_size_name(const void *a, const void *b) {
    const struct file *aa = a;
    const struct file *bb = b;
    if (aa->file_info.st_size < bb->file_info.st_size)
        return -1;
    if (aa->file_info.st_size > bb->file_info.st_size)
        return +1;
    return strcmp(aa->name, bb->name);
}

int main(int argc, char *argv[]) {
    dir_state ds = { "", NULL, 0, 0 };
    int i;

    if (argc < 2) {
        strcpy(ds.path, ".");
        listFilesRecursively(&ds);
    } else {
        for (i = 1; i < argc; i++) {
            strcpy(ds.path, argv[i]);
            listFilesRecursively(&ds);
        }
    }
    printf("\nFiles sorted by name:\n");
    qsort(ds.files, ds.files_count, sizeof(*ds.files), cmp_name);
    for (i = 0; i < ds.files_count; i++) {
        printf("%10ld  %s\n", ds.files[i].file_info.st_size, ds.files[i].name);
    }
    printf("\nFiles sorted by size and name:\n");
    qsort(ds.files, ds.files_count, sizeof(*ds.files), cmp_size_name);
    for (i = 0; i < ds.files_count; i++) {
        printf("%10ld  %s\n", ds.files[i].file_info.st_size, ds.files[i].name);
    }
    for (i = 0; i < ds.files_count; i++) {
        free(ds.files[i].name);
    }
    free(ds.files);
    return 0;
}

注意:

  • 最大深度不受限制:由于此方法遵循符号链接,因此目录树中可能存在循环,导致遍历相同路径多次。但是,由于snprintf强制执行了路径长度限制,因此不会导致无限递归。