C 我在递归函数中声明了一个数组。我该怎么分类呢?

C 我在递归函数中声明了一个数组。我该怎么分类呢?,c,recursion,directory,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;

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

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

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

对于ListFiles的每次递归调用,您在堆栈中使用的字节数超过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;
}

您的方法不起作用:

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

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);
}
以下是修改后的版本:

#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;
}
#包括
#包括
#包括
#包括
#包括
#包括
结构文件{
字符*名称;
结构{
长st_尺寸;
}档案信息;
};
类型定义结构目录状态{
字符路径[1024];
结构文件*文件;
int文件大小;
整数文件计数;
}迪鲁州;
int listfiles递归(dir_state*sp){
结构方向*dp;
结构统计buf;
int计数器=0;
int path_len=strlen(sp->path);
DIR*DIR=opendir(sp->path);
如果(!dir)
返回0;
而((dp=readdir(dir))!=NULL){
如果(strcmp(dp->d_name,“.”)=0和&strcmp(dp->d_name,“…”)!=0){
snprintf(sp->path+path\u len,sizeof(sp->path)-path\u len,“/%s”,dp->d\u name);
如果(sp->files\u count==sp->files\u size){
int new_size=sp->files_size*3/2+16;
结构文件*new\u p=realloc(sp->files,new\u size*sizeof(*new\u p));
if(new_p==NULL)
返回-1;
sp->文件大小=新大小;
sp->files=new\u p;
}
memset(&sp->files[sp->files_count],0,sizeof(struct file));
sp->files[sp->files\u count].name=strdup(sp->path);
如果(!stat(sp->path,&buf))
sp->files[sp->files\u count]。file\u info.st\u size=buf.st\u size;
printf(“%s%s%ld%s\n”,sp->files[sp->files\u count]。名称,“-”,
sp->files[sp->files\u count]。file\u info.st\u size,“字节”);
sp->files_count++;
计数器++;
递归列表文件(sp);
}
}
closedir(dir);
sp->path[path_len]='\0';
返回计数器;
}
int cmp_名称(常量无效*a,常量无效*b){
常量结构文件*aa=a;
常量结构文件*bb=b;
返回strcmp(aa->name,bb->name);
}
int cmp_大小_名称(常量无效*a,常量无效*b){
常量结构文件*aa=a;
常量结构文件*bb=b;
如果(aa->file\u info.st\u sizefile\u info.st\u size)
返回-1;
如果(aa->file\u info.st\u size>bb->file\u info.st\u size)
返回+1;
返回strcmp(aa->name,bb->name);
}
int main(int argc,char*argv[]){
目录状态ds={',NULL,0,0};
int i;
如果(argc<2){
strcpy(ds.path,“.”);
递归地列出文件(&ds);
}否则{
对于(i=1;i
注:

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

这看起来不像C++,它使用的是VLAS,所以它不能是C++(除非它依赖于非标准扩展)。我想把它们保存在一个结构数组中…我的结构类似于
typedef结构文件{char*name;struct stat file_info;}文件但是当我在函数外声明这个数组时,我得到了分段错误。。。因为我不仅需要列出数据,还需要对数据进行操作,比如排序、传输。。。谢谢你的回答@尼克:好的,我编辑了我的答案,一些小改动。必须在堆中分配警告文件,因为如果needed@Nick我不使用固定大小来保存路径名(例如,no
char name[256];
),这两种方法都是为了确保无论路径名的长度如何,都可以保存它,并且在路径名短于保留大小时,也不会白白消耗内存。对于文件也是一样的,我不使用固定大小的向量来管理任何数量的文件,也不使用大量的向量来消耗内存。Nfile不是1到不realloc每次到达一个文件我已经完成了这个项目,但我有最后一个问题。。。我是