试图更好地理解C尺寸

时间:2015-11-03 04:26:54

标签: c

首先,代码有效,但它暂时没有,我试图理解为什么我做了修复它。

所以我有一个功能:

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的次数。

原来我错了......非常非常错。但为什么,我问......

2 个答案:

答案 0 :(得分:4)

如果您未将列表中的最后一个指针设置为NULL,则会在array_size函数中遇到未定义的行为,因为它会滚动到数组末尾(没有标记停止)它和你可能不拥有的内存并没有被初始化。

9的不可预测大小是上述未定义行为的结果。它可能是当时记忆中任何东西的结果。但是,真的,在UB,任何事情都可能发生。

答案 1 :(得分:1)

array_size中的循环最终会开始测试array[i] != NULL,其中i是您使用realloc分配的空间中的最后一个索引。

如果您确实将此条目设置为NULL,那么一切都很顺利。但是如果你没有:未初始化的值与空指针不同。读取未初始化的值可能会导致崩溃,或者编译器可能会基于您从未读过未初始化值的假设来优化程序,因为语言规范说您不打算这样做!

可能的结果是,最后一个条目似乎包含可能与NULL不匹配的垃圾值。然后你的循环继续读取分配空间的末尾,结果不可预测。