我有一个以下字符串(文件名)的列表:{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 ' '
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("%sn", 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;
};
编辑
如果我在char *tmp = concat(list_iter->filename, "/");
后立即添加printf("tmp = %sn", tmp);
,我会得到以下输出:
tmp = Lorem.ipsum/
tmp =
tmp = SENDME/
tmp = LOREM2/
tmp = consectetur/
tmp = adipiscing.elit/
这是一个程序的链接,其中包含我用于此目的的所有代码。如果我运行此测试,它会按预期工作...但是如果我尝试在我的程序生成的列表中运行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/
考虑一下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
不是分配的,而是引用get_file_list
dir
d_name
字段。到目前为止一切顺利,但请记住,每个dir
都属于d
数组,该数组opendir
mallocs,但closedir
释放。closedir
被调用后,它以及其中的所有内容(包括名称)都不复存在。
欢迎来到 UB。