C中的递归和链表

时间:2017-01-14 17:21:54

标签: c file recursion

我正在努力创建一个函数,该函数接收路径并读取其中的所有文件并创建链接列表。阅读目录效果很好,但我很难在链表中创建和存储相关信息,以便以后使用。

这是我目前正在使用的结构:

typedef struct searchPool searchPool;
struct searchPool{

    char * path;
    char * fileName;
    char *pathFile;

    searchPool * next;

};

创建类型' SearchPool'的新元素的功能定义如下:

searchPool * mallocStructPool (char * path, char * fileName, char * filePath ) {

    searchPool * element = (searchPool*)malloc(sizeof(searchPool));
    element->path = malloc(sizeof(char * ));
    element->fileName = malloc(sizeof(char * ));
    element->pathFile = malloc(sizeof(char * ));

    element->path = path;
    element->fileName = fileName;
    element->pathFile = filePath;

    element->next = NULL;

    return element;
}

最后,带有列表头部的递归函数就是这样编写的(如果向右滚动则会注释代码):

void listDir(char * path, searchPool * head){
    DIR * d = opendir(path);        // open the path

    searchPool * element;                                                                   // create new Element of type SearchPool
    struct dirent * dir;                                                                    // for the directory entries

    while ((dir = readdir(d)) != NULL) {                                                    // if we were able to read somehting from the directory
        if(dir-> d_type != DT_DIR) {                                                        // if the type is not directory just print it with blue

            char * s = malloc(sizeof(char*)+1);                                             // variable to concatenate
            s = concat(path, dir->d_name);                                                  // concatenate path and filename together
            //printf("%s\n",s);

            element = mallocStructPool(dir->d_name, path, s);                               // malloc new element and set variables

            head->next = element;
            element->next = NULL;

            free(s);

        } else 
        if(dir -> d_type == DT_DIR && strcmp(dir->d_name,".")!=0 && strcmp(dir->d_name,"..")!=0 ) {// if it is a directory
            char d_path[255];                                                               // here I am using sprintf which is safer than strcat
            sprintf(d_path, "%s/%s", path, dir->d_name);
            listDir(d_path, element);                                                       // recall with the new path
        }
    }
    closedir(d);                                                                            // finally close the directory
}

问题在于,当调用函数listDir()时,它最终只会打印我在其中提供的第一个路径,其余部分将被忽略。每次运行后我是否必须在listDir()中返回新元素?我不知道自己哪里出错了。

感谢任何帮助。谢谢你的时间。

2 个答案:

答案 0 :(得分:3)

您的代码没有意义。您不需要为其成员分配结构。另外,不要cast the return of malloc。你没有检查malloc()的回报。而且你不会复制字符串。

在你的第二个函数中,你应该返回链表并检查opendir()的返回函数。

这是一个例子:

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

typedef struct searchPool searchPool;
struct searchPool {
  char *path;
  char *fileName;
  char *pathFile;
  searchPool *next;
};

static searchPool *mallocStructPool(char *path, char *fileName) {

  searchPool *element = malloc(sizeof *element);
  if (element == NULL) {
    goto error;
  }

  size_t path_size = strlen(path);
  element->path = malloc(path_size + 1);
  if (element->path == NULL) {
    goto free_element;
  }

  size_t fileName_size = strlen(fileName);
  element->fileName = malloc(fileName_size + 1);
  if (element->fileName == NULL) {
    goto free_path;
  }

  element->pathFile = malloc(path_size + 1 + fileName_size + 1);
  if (element->pathFile == NULL) {
    goto free_fileName;
  }

  memcpy(element->path, path, path_size);
  element->path[path_size] = '\0';

  memcpy(element->fileName, fileName, fileName_size);
  element->fileName[fileName_size] = '\0';

  memcpy(element->pathFile, path, path_size);
  element->pathFile[path_size] = '/';
  memcpy(element->pathFile + path_size + 1, fileName, fileName_size);
  element->pathFile[path_size + 1 + fileName_size] = '\0';

  return element;
free_fileName:
  free(element->fileName);
free_path:
  free(element->path);
free_element:
  free(element);
error:
  return NULL;
}

searchPool *listDir(char *path);

static searchPool *listDir_aux(char *path, struct dirent *dirent) {
  if (dirent->d_type == DT_DIR && dirent->d_type != DT_LNK &&
      strcmp(dirent->d_name, ".") != 0 && strcmp(dirent->d_name, "..") != 0) {
    size_t path_size = strlen(path);
    size_t name_size = strlen(dirent->d_name);
    char *d_path = malloc(path_size + 1 + name_size + 1);
    if (d_path == NULL) {
      return NULL;
    }

    memcpy(d_path, path, path_size);
    d_path[path_size] = '/';
    memcpy(d_path + path_size + 1, dirent->d_name, name_size);
    d_path[path_size + 1 + name_size] = '\0';

    searchPool *ret = listDir(d_path);

    free(d_path);

    return ret;
  }
  return mallocStructPool(path, dirent->d_name);
}

searchPool *listDir(char *path) {
  printf("%s\n", path);
  DIR *dir = opendir(path);
  if (dir == NULL) {
    perror("dir()");
    return NULL;
  }

  searchPool *head = NULL;

  struct dirent *dirent;
  while ((dirent = readdir(dir)) != NULL) {
    searchPool *elem = listDir_aux(path, dirent);
    if (elem != NULL) {
      elem->next = head;
      head = elem;
    }
  }
  closedir(dir);

  return head;
}

int main(void) {
  searchPool *head = listDir("/tmp");
  searchPool *tmp;
  for (searchPool *elem = head; elem != NULL; elem = tmp) {
    printf("%s, %s, %s\n", elem->path, elem->fileName, elem->pathFile);
    free(elem->path);
    free(elem->fileName);
    free(elem->pathFile);
    tmp = elem->next;
    free(elem);
  }
}

答案 1 :(得分:0)

向尾部添加元素

 searchPool *ptr;
 searchPool *prev = 0;
 searchPool *head = something;

 for(ptr = head; ptr != NULL; ptr = ptr->next)
   prev = ptr;
 element->next = 0;
 prev->next = element;

添加到头部(更快)

 element->next = head;
 head = element;

注意头部现在不稳定。

在头部后添加一个

element->next = head->next;
head->next = element

请注意,head现在可能是一个没有任何虚拟节点的虚拟节点 其中的数据,为了具有稳定性而存在 和链接列表的常量“head”指针;