I have to recursively list all the subdirectories of a given directory and I got it working, but it lists them out of order. I want it to list all the subdirectories of the given directory and then move on to the next subdirectory and I know it's because my recursion is inside the while loop, but I haven't been able to figure out how to implement it outside the loop. I thought about making an array of strings with the paths of the subdirectory and use it as a stack, but after looking it up, I don't think that is possible.
#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;
}
To print the directory structure in a BFS, you could use a queue. Since C doesn't have such a thing in its standard library, you have to roll your own or use a library. Here's a simple example of how this might work, alongside a cleaned up version of your 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;
}
Output:
== 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
A few remarks and suggestions on your code:
sizeof(name) + sizeof(subName)
is incorrect. sizeof
returns the size of the pointers; strlen
is probably what you intended to get the lengths of the pointed-to strings. This avoids undefined behavior due to possibly strcat
-ing beyond the allocated memory.free
memory after use to avoid memory leaks.-Wall
flag to turn warnings on reveals that control reaches the end of a non-void function. Change your return type from int
to void
if you're not actually returning an integer.