递归列出给定目录的所有子目录

问题描述 投票:0回答:2

我必须递归列出给定目录的所有子目录,但我可以使它正常工作,但是却无序列出了它们。我希望它列出给定目录的所有子目录,然后转到下一个子目录,我知道这是因为我的递归位于while循环内,但是我无法弄清楚如何在循环外实现它。我曾考虑过用子目录的路径创建一个字符串数组并将其用作堆栈,但是在查找之后,我认为这是不可能的。

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

int listDir(char *name)
{
    DIR *dir;
    struct dirent *cDir;

    dir = opendir(name);
    if(dir != NULL)
    {
        while((cDir=readdir(dir)) != NULL)
        {
            char* subName = cDir->d_name;       
            if(strcmp(subName, ".")==0 || strcmp(subName, "..")==0)
                continue;
            else
            {
                //  Checks if it's a directory
                if(cDir->d_type == DT_DIR)        
                {
                    printf("%s\n", subName);
                    char *path;
                    path = malloc(sizeof(name) + sizeof(subName) + 2);
                    strcat(path, name);
                    strcat(path, "/");
                    strcat(path, subName);
                    listDir(path);                  
                }   
            }
        }


        closedir(dir);
    }

}

int main(int argc, char *argv[])
{   
    printf("%s\n", argv[1]);
    listDir(argv[1]);

    return 0;
}
c recursion directory subdirectory
2个回答
1
投票

要在BFS中打印目录结构,可以使用队列。由于C标准库中没有这样的东西,因此您必须自己滚动或使用一个库。这是一个简单的示例,说明了它如何工作以及DFS的清理版本。

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

void listDirBFS(char *name)
{
    int q_front = 0;
    int q_back = 1;
    int q_cap = 4;
    char **q = malloc(q_cap * sizeof(*q));

    for (q[0] = strdup(name); q_front != q_back;) 
    {
        name = q[q_front++];
        DIR *dir = opendir(name);

        if (!dir) continue;

        printf("%s\n", name);
        size_t name_len = strlen(name);
        struct dirent *cDir;

        while ((cDir = readdir(dir)))
        {
            char *subName = cDir->d_name;

            if (strcmp(subName, ".") && strcmp(subName, "..") &&
                cDir->d_type == DT_DIR)
            {
                char *path = malloc(name_len + strlen(subName) + 2);
                sprintf(path, "%s/%s", name, subName);

                if (q_back >= q_cap && 
                    !(q = realloc(q, sizeof(*q) * (q_cap *= 2)))) 
                {
                    fprintf(stderr, "%s:%d realloc\n", __FILE__, __LINE__);
                    exit(1);
                }

                q[q_back++] = path;
            }
        }

        free(name);         
        closedir(dir);
    }

    free(q);
}

void listDir(char *name)
{
    DIR *dir = opendir(name);

    if (!dir) return;

    printf("%s\n", name);
    size_t name_len = strlen(name);
    struct dirent *cDir;

    while ((cDir = readdir(dir)))
    {
        char *subName = cDir->d_name;

        if (strcmp(subName, ".") && strcmp(subName, "..") &&
            cDir->d_type == DT_DIR)
        {
            char *path = malloc(name_len + strlen(subName) + 2);
            sprintf(path, "%s/%s", name, subName);
            listDir(path);
            free(path);
        }
    }

    closedir(dir);
}

int main(int argc, char **argv)
{   
    puts("== DFS ==");
    listDir(".");
    puts("\n== BFS ==");
    listDirBFS(".");
    return 0;
}

输出:

== DFS ==
.
./a
./a/b
./a/b/e
./a/bb
./a/bb/f
./a/bb/f/g
./aa
./aa/c
./aaa
./aaa/d
./aaa/d/h
./aaa/d/hh

== BFS ==
.
./a
./aa
./aaa
./a/b
./a/bb
./aa/c
./aaa/d
./a/b/e
./a/bb/f
./aaa/d/h
./aaa/d/hh
./a/bb/f/g

关于您的代码的几点评论和建议:

  • sizeof(name) + sizeof(subName)不正确。 sizeof返回指针的大小; strlen可能是您想要获得指向的字符串的长度的目的。这样可以避免由于strcat超出分配的内存而导致的未定义行为。
  • 使用后始终保持free内存以避免内存泄漏。
  • 使用-Wall标志进行编译以打开警告,这表明控制已到达非无效函数的末尾。如果您实际上没有返回整数,请将返回类型从int更改为void
  • 请注意,我更改了打印位置。您可以将它们移回递归调用的位置,但是在探索子级之前,我更喜欢对函数顶部的每个节点进行操作。算法基本相同。

1
投票

我必须递归列出给定目录的所有子目录

请注意,目录对于C11标准是未知的。通过阅读n1570进行检查。与目录相关的API是operating system特定的。在Windows上是WinAPI

在Linux系统上,您应该使用nftw(3);它会为您完成大部分工作。或考虑使用Glib之类的库。

您将向某个函数传递一些函数,这些函数会填充(和/或nftw)一些指向经过仔细定义的realloc的全局指针

注意structGNU findutils。您可以研究其源代码以获取灵感。

注意free softwaresash具有内置的busybox命令,并且为find。您可以研究其源代码以获取灵感。

open source(还有zsh shell)具有强大的外壳扩展功能,包括像zsh这样的递归fish shell,因此您可以研究其源代码以获取灵感。

© www.soinside.com 2019 - 2024. All rights reserved.