如何将目录名称正确存储到链接列表中?

时间:2019-08-22 15:20:57

标签: c memory-management malloc singly-linked-list c-strings

我正在尝试将目录和子目录的名称存储在链接列表中。当我使用printf显示它们时,名称会正确列出,但是当我尝试将它们存储在链接列表中时,它们不会正确显示。

当我只是打印时,所有东西都起作用,但是当我将字符串存储到链接列表中并显示它时,结果会有所不同。

void ls_r(char *path) {
    DIR *dir;
    struct dirent *file;
    struct stat buf;
    char *temp;
    t_list *list;

    if (!(dir = opendir(path)))
        return;
    list = NULL;
    while ((file = readdir(dir)) != NULL) {
        if (file->d_name[0] != '.') {
            temp = strdup(path);
            strcat(temp, "/");
            strcat(temp, file->d_name);
            stat(temp, &buf);
            if (buf.st_mode && S_ISDIR(buf.st_mode)) {
                ft_list_insert(&list, temp);
                printf("%s\n", temp);
                ls_r(temp);
            }
        }
    }
    ft_print_list(list, "\n");
}

printf结果:

./file3
./file3/file32
./file3/file33
./file3/file31
./file3/file31/file311
./file3/file31/file313
./file3/file31/file312
./file2
./file1
./file1/file11
./file1/file12
./file1/file13

链接列表结果:

./file3/file31/f .@��
./file3/file31/f�-@��
./file3/file31/f./file3/file31
./file3/file33
./file3/file32./file1/file13
./file1/file12
./file1/file11./file1
./file2
./file3

3 个答案:

答案 0 :(得分:2)

这些声明

        temp = strdup(path);
        strcat(temp, "/");
        strcat(temp, file->d_name);

无效。

您必须保留足够的空间以包含字符串path"/"file->d_name的串联。

例如使用

temp = malloc( strlen( path ) + sizeof( ( char )'/' ) + strlen( file->d_name ) + sizeof( ( char )'\0' ) );

,然后将字符串复制到分配的内存中。

strcpy( temp, path );
strcat(temp, "/");
strcat(temp, file->d_name);

此外,未显示其代码的函数ft_list_insert可能无法在列表中正确插入节点。

答案 1 :(得分:0)

您的代码具有未定义的行为,因为您在strdup分配的字符串的末尾复制了多余的字符。您必须为完整的字符串分配足够的空间。

还请注意,所有不是目录的条目都存在内存泄漏,应该在返回之前释放列表。如果ft_list_insert()复制该路径,则也应释放该路径。

测试buf.st_mode似乎没有用,但是测试stat失败是必要的,以避免读取buf结构的未初始化内容。

这是具有实用程序功能的修改版本:

char *makepath(const char *dir, const char *name) {
    size_t len1 = strlen(dir);
    size_t len2 = strlen(name);
    // allocate extra space for '/' and '\0'
    size size = len1 + len2 + 2;
    char *p = malloc(size);
    if (p != NULL) {
        // copy the directory part
        memcpy(p, dir, len1);
        if (len1 > 0 && dir[len - 1] != '/') {
            // only append a path separator if needed
            p[len1++] = '/';
        }
        // copy the filename and its null terminator
        memcpy(p + len1, name, len2 + 1);
    }
    return p;
}

void ls_r(const char *path) {
    DIR *dir;
    struct dirent *file;
    struct stat buf;
    char *temp;
    t_list *list;

    if (!(dir = opendir(path)))
        return;
    list = NULL;
    while ((file = readdir(dir)) != NULL) {
        if (file->d_name[0] != '.') {
            temp = makepath(path, file->d_name);
            if (temp != NULL && !stat(temp, &buf) && S_ISDIR(buf.st_mode)) {
                ft_list_insert(&list, temp);
                printf("%s\n", temp);
                ls_r(temp);
            } else {
                free(temp);
            }
        }
    }
    ft_print_list(list, "\n");
    ft_free_list(list);  // assuming ft_free_list() also frees the list payload
}

答案 2 :(得分:0)

这是工作代码:

更改 :(在@chqrlie更改之上完成)

  1. 已添加主函数来调用ls_r()函数。
  2. 在将实际路径写入同一内​​存位置之前,先为“ char * temp”分配堆内存。
  3. 添加了单链接列表实用程序功能以维护目录列表。
  4. 已删除ft_print_list(列表,“ \ n”);从ls_r()调用,因为它被递归调用。将具有不同函数名称(print_list())的同一调用移至主函数。

基本上,您需要妥善处理内存分配和释放。否则,您会遇到这类问题。

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

/* directory node structure */
struct dir_node
{
    char *path;
    struct dir_node *next;
};

typedef struct dir_node dnode;

/* Global pointers, these can be moved to main() function
 * and can be passed to the required functions.
 * To do that you will have to use double pointers(pointer to pointer).
 * Just for understanding making these as global.
 */

dnode *newnode,*temp;
dnode *list = NULL, *last = NULL;

/*
 * Creating new node.
 */
dnode* create_node(char* path)
{
    newnode = (dnode *)malloc(sizeof(dnode));
    if (newnode == NULL)
    {
        printf("\nMemory was not allocated");
        return NULL;
    }
    else
    {
        int path_len = strlen(path);
        //make sure we have received valid path.
        if(path_len <= 0)
        {
            free(newnode);
            newnode=NULL;
            return NULL;
        }
        newnode->path = path;
        newnode->next = NULL;
        return newnode;
    }
}
/*
 * Insert new node at the end of the list.
 */
void insert_node(char* path)
{
    newnode = create_node(path);
    if(newnode == NULL)
    {
        //Something went wrong.
        //Either path is invalid or memory is not allocated properly.
        return;
    }
    if (list == last && last == NULL)
    {
        //First node in the list.
        list = last = newnode;
        list->next = NULL;
        last->next = NULL;
    }
    else
    {
        last->next = newnode;
        last = newnode;
        last->next = NULL;
    }
}
/*
 * Print the list.
 */
void print_list()
{
    temp=list;
    while(temp!=NULL)
    {
        printf("%s\n",temp->path);
        temp=temp->next;
    }
    printf("\n");

}
/*
 * Clear the list.
 */
void clear_list()
{
    dnode* current = list;
    dnode* next;

    while (current != NULL)
    {
        next = current->next;
        if(current->path != NULL)
        {
            free(current->path);
            current->path=NULL;
        }
        free(current);
        current = next;
    }
    list = NULL;
    temp=list;
}
char *create_path(const char *dir, const char *name) {
    size_t len1 = strlen(dir);
    size_t len2 = strlen(name);
    // allocate extra space for '/' and '\0'
    size_t size = len1 + len2 + 2;
    char *p = (char *)malloc(sizeof(char)*size);
    if (p != NULL) {
        // copy the directory part
        memcpy(p, dir, len1);
        if (len1 > 0 && dir[len1 - 1] != '/') {
            // add a path separator if needed
            p[len1++] = '/';
        }
        // copy the filename and its null terminator
        memcpy(p + len1, name, len2 + 1);
    }
    return p;
}

void ls_r(const char *path) {
    DIR *dir;
    struct dirent *file;
    struct stat buf;
    char *temp=NULL;

    if (!(dir = opendir(path)))
        return;
    while ((file = readdir(dir)) != NULL) {
        if (file->d_name[0] != '.') {
            temp = create_path(path, file->d_name);
            if (temp != NULL && !stat(temp, &buf) && S_ISDIR(buf.st_mode)) {
                printf("%s\n", temp);
                insert_node(temp);
                ls_r(temp);
            } else {
                free(temp);
            }
        }
    }
}
int main()
{
    ls_r("/work/Workspace/");
    printf(".....Directory list:....\n");
    print_list();
    clear_list();
    printf(".....Directory list after clearing:....\n");
    print_list();
    printf("...done....\n");
    return 0;
}