打印文件名列表时缺少第二个节点:为什么?

时间:2018-01-20 14:38:24

标签: c string concatenation

我有以下字符串(文件名)的列表:{Lorem.ipsum, dolor-sit-amet, SENDME, LOREM2, consectetur, adipiscing.elit}。 我写了这个函数,它应该占用列表的每个节点并生成一个由所有文件名组成的单个字符串(在每个条目之间插入/)。

char *file_list_tostring(struct file_list *file_list) {
    char *final_string = NULL;
    size_t final_len = 0;
    struct file_node *list_iter = file_list->first;
    while (list_iter != NULL) {
        char *tmp = concat(list_iter->filename, "/");
        size_t tmp_len = strlen(tmp);
        char *s = realloc(final_string, final_len + tmp_len + 1); // +1 for '\0'
        if (s == NULL) {
            perror("realloc");
            exit(EXIT_FAILURE);
        }
        final_string = s;
        memcpy(final_string + final_len, tmp, tmp_len + 1);
        final_len += tmp_len;
        list_iter = list_iter->next;
    }
    printf("%s\n", final_string);
    return final_string;
}

以下是concat()函数的实现:

char *concat(const char *s1, const char *s2) {
    char *result = malloc(strlen(s1) + strlen(s2) + 1); //+1 for the null-terminator
    if (result == NULL) {
        perror("malloc");
        return NULL;
    }
    strcpy(result, s1);
    strcat(result, s2);
    return result;
}

如果我运行file_list_tostring(),我会得到以下输出:

Lorem.ipsum/SENDME/LOREM2/consectetur/adipiscing.elit/

如您所见,列表的第二个条目(dolor-sit-amet)没有出现。这真让我感到惊讶!原因是什么?

注意:我尝试的任何文件名列表都会跳过第二个文件名。

以下是定义列表的结构:

struct file_node {
    char *filename;
    struct file_node *prev, *next;
};

struct file_list {
    struct file_node *first, *last;
};

修改

如果我在printf("tmp = %s\n", tmp);之后添加char *tmp = concat(list_iter->filename, "/");,我会得到以下输出:

tmp = Lorem.ipsum/
tmp = 
tmp = SENDME/
tmp = LOREM2/
tmp = consectetur/
tmp = adipiscing.elit/

这是一个程序的link,其中包含我用于此的所有代码。如果我运行此测试它按预期工作...但是如果我尝试在我的程序生成的列表上运行file_list_print(),稍后file_list_tostring我会得到不同的结果(如前所述,第二个条目不见了)。我不得不假设列表没有正确生成(而是在测试文件中)。

所以这是我用来获取列表的代码(它应该在repository目录中获取所有文件名):

struct file_list *get_file_list() {
    struct file_list *list = file_list_init();
    DIR *d;
    struct dirent *dir;
    d = opendir("./repository");
    if (d == NULL)
        return NULL;
    while ((dir = readdir(d)) != NULL) {
        struct file_node *newnode;
        if (!(!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")) && dir->d_type == DT_REG) {
            newnode = file_node_init(dir->d_name);
            file_node_add(list, newnode);
        }
    }
    closedir(d);
    return list;
}

我尝试更改目录中的所有文件,这次我得到以下2个输出:

0: FILEC
1: FILEE
2: FILEB
3: FILED
4: FILEA

tmp = FILEC/
tmp = 
tmp = 
tmp = FILED/
tmp = FILEA/

FILEC/FILED/FILEA/

1 个答案:

答案 0 :(得分:1)

考虑如何实施file_node_init

struct file_node *file_node_init(char *filename) {
    struct file_node *node = malloc(sizeof(struct file_node));
    if (node == NULL)           // Error in malloc
        return NULL;
    node->filename = filename;
    node->prev = NULL;
    node->next = NULL;
    return node;
}

请注意,node->filename未分配,但引用d_name dir的{​​{1}}字段。到目前为止一直很好,但请记住,每个get_file_list属于dir数组,d mallocs,opendir 释放。调用closedir后,它将不再存在,连同其中的所有内容,包括名称。

欢迎来到UB。