首先,代码有效,但它暂时没有,我试图理解为什么我做了修复它。
所以我有一个功能:
int array_size(const char **array) {
int i = 0;
while (array[i] != NULL) ++i;
return i;
}
我也有这个指针,我从一个元素开始,并调用一个修改local_mig的函数:
int main(void) {
char **local_mig = malloc(sizeof(char *) * 1);
populate_local_mig(&local_mig);
int size = array_size(local_mig); // 9
}
此功能如下所示(注意第二行到最后一行的注释):
void populate_local_mig(char ***local_mig) {
// ...above here reads a directory with 5 .sql files
while ((directory = readdir(dir)) != NULL) {
int d_name_len = strlen(directory->d_name);
char *file_name = malloc(sizeof(char) * (d_name_len + 1));
strcpy(file_name, (const char *)directory->d_name);
size_t len = strlen(file_name);
if (len > 4 && strcmp(file_name + len - 4, ".sql") == 0) {
(*local_mig)[i] = malloc(sizeof(char) * (len + 1));
strcpy((*local_mig)[i], file_name);
++i;
*local_mig = realloc(*local_mig, sizeof(char *) * (i + 1));
}
}
//(*local_mig)[i] = NULL;
}
还在我身边吗?好。
稍后,我打电话给array_size(local_mig);
然后它会返回9.什么?我期待5.当我稍后迭代local_mig
时,我最终会在尝试读取第6个元素时发生段错误。
所以,我添加了(*local_mig)[i] = NULL;
,然后突然一切正常,它返回5,就像它应该有的一样。
我一直认为,因为我分配了足够的空间来容纳每个字符数组,所以大小显然是我调整大小local_mig
的次数。
原来我错了......非常非常错。但为什么,我问......
答案 0 :(得分:4)
如果您未将列表中的最后一个指针设置为NULL,则会在array_size
函数中遇到未定义的行为,因为它会滚动到数组末尾(没有标记停止)它和你可能不拥有的内存并没有被初始化。
9
的不可预测大小是上述未定义行为的结果。它可能是当时记忆中任何东西的结果。但是,真的,在UB,任何事情都可能发生。
答案 1 :(得分:1)
array_size
中的循环最终会开始测试array[i] != NULL
,其中i
是您使用realloc
分配的空间中的最后一个索引。
如果您确实将此条目设置为NULL
,那么一切都很顺利。但是如果你没有:未初始化的值与空指针不同。读取未初始化的值可能会导致崩溃,或者编译器可能会基于您从未读过未初始化值的假设来优化程序,因为语言规范说您不打算这样做!
可能的结果是,最后一个条目似乎包含可能与NULL
不匹配的垃圾值。然后你的循环继续读取分配空间的末尾,结果不可预测。