C 2D阵列损坏

时间:2017-03-11 07:36:30

标签: c arrays

我遇到了2D阵列损坏的问题。请考虑以下代码:

int **generate_clique_adjacency_matrix(const formula f) {
    int num_terms = f.num_clauses * kVarsPerClause;
    printf("\nnum_terms: %d\n", num_terms);

    // construct a 2D array of appropriate size
    int **compatible = malloc(sizeof(int) * num_terms);
    for (int i = 0; i < num_terms; i++) {
        compatible[i] = malloc(sizeof(int) * num_terms);
        // initialize every cell to 0
        for (int j = 0; j < num_terms; j++) {
            printf("writing 0 to (%d, %d)\n", i, j);
            compatible[i][j] = 0;
        }
    }

    printf("num_terms: %d\n", num_terms);
    printf("matrix:\n");
    for (int i = 0; i < num_terms; i++) {
        printf("row %d: ", i);
        for (int j = 0; j < num_terms; j++) {
            printf("%d ", compatible[i][j]);
        }
        printf("\n");
    }
    exit(0);
}

产生令人震惊的产出:

num_terms: 6
writing 0 to (0, 0)
writing 0 to (0, 1)
writing 0 to (0, 2)
writing 0 to (0, 3)
writing 0 to (0, 4)
writing 0 to (0, 5)
writing 0 to (1, 0)
writing 0 to (1, 1)
writing 0 to (1, 2)
writing 0 to (1, 3)
writing 0 to (1, 4)
writing 0 to (1, 5)
writing 0 to (2, 0)
writing 0 to (2, 1)
writing 0 to (2, 2)
writing 0 to (2, 3)
writing 0 to (2, 4)
writing 0 to (2, 5)
writing 0 to (3, 0)
writing 0 to (3, 1)
writing 0 to (3, 2)
writing 0 to (3, 3)
writing 0 to (3, 4)
writing 0 to (3, 5)
writing 0 to (4, 0)
writing 0 to (4, 1)
writing 0 to (4, 2)
writing 0 to (4, 3)
writing 0 to (4, 4)
writing 0 to (4, 5)
writing 0 to (5, 0)
writing 0 to (5, 1)
writing 0 to (5, 2)
writing 0 to (5, 3)
writing 0 to (5, 4)
writing 0 to (5, 5)
num_terms: 6
matrix:
row 0: 22661104 0 22661136 0 0 0 
row 1: 0 0 0 0 0 0 
row 2: 0 0 0 0 0 0 
row 3: 0 0 0 0 0 0 
row 4: 0 0 0 0 0 0 
row 5: 0 0 0 0 0 0 

我的阵列是如何被破坏的?显然,第0行中的数据应全为零。我甚至尝试添加断言以确保malloc成功。这让我疯了。

3 个答案:

答案 0 :(得分:4)

这是错误的:

int **compatible = malloc(sizeof(int) * num_terms);

您需要为 n 指向int预留空间(不适用于 n int

更改为

int **compatible = malloc(sizeof(int *) * num_terms);

或更好

int **compatible = malloc(sizeof(*compatible) * num_terms);

答案 1 :(得分:2)

改变这个:

int **compatible = malloc(sizeof(int) * num_terms);

到此:

int **compatible = malloc(sizeof(int *) * num_terms);

因为第一个维度是一个指针数组。

不要忘记最后释放内存:

 for (int i = 0; i < num_terms; i++)
    free(compatible[i]);
 free(compatible);

答案 2 :(得分:1)

正如其他答案中所指出的,第一次分配需要为指向int而不是int的指针分配空间。最好在sizeof操作数中使用标识符而不是显式类型,以避免在此处出错。此外,您需要检查malloc()的返回值是否存在分配错误:

int **compatible = malloc(sizeof(*compatible) * num_terms);
if (compatible == NULL) {
    fprintf(stderr, "Row allocation error\n");
    exit(EXIT_FAILURE);
}

for (int i = 0; i < num_terms; i++) {
    compatible[i] = malloc(sizeof(**compatible) * num_terms);
    if (compatible[i] == NULL) {
        fprintf(stderr, "Column allocation error\n");
        exit(EXIT_FAILURE);
    }

    // initialize every cell to 0
    for (int j = 0; j < num_terms; j++) {
        printf("writing 0 to (%d, %d)\n", i, j);
        compatible[i][j] = 0;
    }
}

更好的方法是在分配中使用VLA,为num_terms num_terms的{​​{1}}数组分配空间,并将结果分配给指向数组的指针int的。{这种方法的优点是分配的内存是连续的,如果分配失败,int将返回空指针。您还应该将malloc()类型用于数组索引,因为此类型可以保证能够保存任何数组索引。

size_t

如果您的阵列不是太大(这取决于系统),您可以简单地使用VLA。请注意,无法检测到VLA的分配错误。

int (*compatible)[num_terms] = malloc(sizeof(*compatible) * num_terms);
if (compatible == NULL) {
    fprintf(stderr, "Allocation error\n");
    exit(EXIT_FAILURE);
}
// initialize every cell to 0
for (size_t i = 0; i < num_terms; i++) {
    for (size_t j = 0; j < num_terms; j++) {
        printf("writing 0 to (%zu, %zu)\n", i, j);
        compatible[i][j] = 0;
    }
}