分配多维数组后内存泄漏

时间:2015-04-03 12:33:45

标签: c arrays matrix multidimensional-array memory-leaks

我写了一个简单的程序来读取任何方阵并计算其行列式。然而,根据Valgrind的说法,它似乎是在泄漏记忆。

示例会话:

./det
4 23 4
2 -5 2
45 2 40
330.000000

这是Valgrind输出:

valgrind --leak-check=full --track-origins=yes ./det                                                                                                  ⏎
==5586== Memcheck, a memory error detector
==5586== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==5586== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==5586== Command: ./det
==5586== 
4 23 4
==5586== Conditional jump or move depends on uninitialised value(s)
==5586==    at 0x4C2D1CA: strcat (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400EE6: readline (det.c:132)
==5586==    by 0x400B13: parse_into (det.c:53)
==5586==    by 0x40084D: main (det.c:20)
==5586==  Uninitialised value was created by a heap allocation
==5586==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x4C2C33F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400EB4: readline (det.c:127)
==5586==    by 0x400B13: parse_into (det.c:53)
==5586==    by 0x40084D: main (det.c:20)
==5586== 
2 -5 2
==5586== Conditional jump or move depends on uninitialised value(s)
==5586==    at 0x4C2D1CA: strcat (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400EE6: readline (det.c:132)
==5586==    by 0x400C66: parse_into (det.c:79)
==5586==    by 0x40084D: main (det.c:20)
==5586==  Uninitialised value was created by a heap allocation
==5586==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x4C2C33F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400EB4: readline (det.c:127)
==5586==    by 0x400C66: parse_into (det.c:79)
==5586==    by 0x40084D: main (det.c:20)
==5586== 
45 2 40
==5586== Invalid read of size 8
==5586==    at 0x400929: determinant (det.c:37)
==5586==    by 0x400864: main (det.c:21)
==5586==  Address 0x51d9040 is 0 bytes inside a block of size 64 free'd
==5586==    at 0x4C2C29E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400D39: allocate_matrix (det.c:95)
==5586==    by 0x400BFB: parse_into (det.c:72)
==5586==    by 0x40084D: main (det.c:20)
==5586== 
==5586== Conditional jump or move depends on uninitialised value(s)
==5586==    at 0x400945: determinant (det.c:37)
==5586==    by 0x400864: main (det.c:21)
==5586==  Uninitialised value was created by a heap allocation
==5586==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x4C2C33F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400DBD: allocate_matrix (det.c:102)
==5586==    by 0x40083D: main (det.c:19)
==5586== 
==5586== Conditional jump or move depends on uninitialised value(s)
==5586==    at 0x40094F: determinant (det.c:37)
==5586==    by 0x400864: main (det.c:21)
==5586==  Uninitialised value was created by a heap allocation
==5586==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x4C2C33F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400DBD: allocate_matrix (det.c:102)
==5586==    by 0x40083D: main (det.c:19)
==5586== 
0.000000
==5586== Invalid read of size 8
==5586==    at 0x400E24: free_matrix (det.c:113)
==5586==    by 0x40087F: main (det.c:22)
==5586==  Address 0x51d9040 is 0 bytes inside a block of size 64 free'd
==5586==    at 0x4C2C29E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400D39: allocate_matrix (det.c:95)
==5586==    by 0x400BFB: parse_into (det.c:72)
==5586==    by 0x40084D: main (det.c:20)
==5586== 
==5586== Invalid free() / delete / delete[] / realloc()
==5586==    at 0x4C2B200: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400E4B: free_matrix (det.c:114)
==5586==    by 0x40087F: main (det.c:22)
==5586==  Address 0x51d9040 is 0 bytes inside a block of size 64 free'd
==5586==    at 0x4C2C29E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400D39: allocate_matrix (det.c:95)
==5586==    by 0x400BFB: parse_into (det.c:72)
==5586==    by 0x40084D: main (det.c:20)
==5586== 
==5586== 
==5586== HEAP SUMMARY:
==5586==     in use at exit: 624 bytes in 14 blocks
==5586==   total heap usage: 17 allocs, 4 frees, 761 bytes allocated
==5586== 
==5586== 8 bytes in 1 blocks are definitely lost in loss record 1 of 6
==5586==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x4C2C33F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400EB4: readline (det.c:127)
==5586==    by 0x400B13: parse_into (det.c:53)
==5586==    by 0x40084D: main (det.c:20)
==5586== 
==5586== 8 bytes in 1 blocks are definitely lost in loss record 2 of 6
==5586==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x4C2C33F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400EB4: readline (det.c:127)
==5586==    by 0x400C66: parse_into (det.c:79)
==5586==    by 0x40084D: main (det.c:20)
==5586== 
==5586== 64 bytes in 1 blocks are definitely lost in loss record 3 of 6
==5586==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400B41: parse_into (det.c:59)
==5586==    by 0x40084D: main (det.c:20)
==5586== 
==5586== 96 (24 direct, 72 indirect) bytes in 1 blocks are definitely lost in loss record 5 of 6
==5586==    at 0x4C2C29E: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400D39: allocate_matrix (det.c:95)
==5586==    by 0x400BFB: parse_into (det.c:72)
==5586==    by 0x40084D: main (det.c:20)
==5586== 
==5586== 448 bytes in 7 blocks are definitely lost in loss record 6 of 6
==5586==    at 0x4C29F90: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x4C2C33F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==5586==    by 0x400DBD: allocate_matrix (det.c:102)
==5586==    by 0x40083D: main (det.c:19)
==5586== 
==5586== LEAK SUMMARY:
==5586==    definitely lost: 552 bytes in 11 blocks
==5586==    indirectly lost: 72 bytes in 3 blocks
==5586==      possibly lost: 0 bytes in 0 blocks
==5586==    still reachable: 0 bytes in 0 blocks
==5586==         suppressed: 0 bytes in 0 blocks
==5586== 
==5586== For counts of detected and suppressed errors, rerun with: -v
==5586== ERROR SUMMARY: 13 errors from 12 contexts (suppressed: 0 from 0)

我不知道为什么,但在Valgrind会议期间结果是错误的!如何使用相同的输入输出3300? Valgrind错误是否值得信任?

这是完整的代码。如您所见,我在使用堆后总是调用free()

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#define MATRIX 8
#define CHUNK 32

double determinant(double **, size_t);
size_t parse_into(double **);
double **allocate_matrix(double **, size_t);
void free_matrix(double **);
char *readline();


int main(int argc, char *argv[]) {
    double **matrix = NULL;
    size_t N;
    matrix = allocate_matrix(matrix, MATRIX);
    N = parse_into(matrix);
    printf("%lf\n", determinant(matrix, N));
    free_matrix(matrix);
    return 0;
}


double determinant(double **matrix, size_t side) {
    if (side == 1) {
        return matrix[0][0];
    } else if (side == 2) {
        return matrix[0][0] * matrix[1][1] - matrix[0][1] * matrix[1][0];
    }

    // Make the matrix triangular
    int i, j, t, r = 1;
    for (j = 0; j < side; j++) {
        if (!matrix[j][j]) return 0;
        for (i = j + 1; i < side; i++) {
            double ratio = matrix[i][j] / matrix[j][j];
            for (t = 0; t < side; t++) {
                matrix[i][t] -= ratio * matrix[j][t];
            }
        }
    }
    for (i = 0; i < side; i++) {
        r *= matrix[i][i];
    }
    return r;
}


size_t parse_into(double **matrix) {
    char *row = readline();
    size_t t;
    size_t N = 0, M = 0;
    size_t i = 1, j = 0;

    int *first_row;
    if (!(first_row = malloc(MATRIX * sizeof(first_row)))) {
        puts("Could not allocate memory.");
        exit(EXIT_FAILURE);
    }
    char *number = strtok(row, " ");
    while (number) {
        if (N == MATRIX) {
            first_row = realloc(first_row, 2 * N * sizeof(first_row));
        }
        first_row[N++] = atoi(number);
        number = strtok(NULL, " ");
    }
    M = N;
    matrix = allocate_matrix(matrix, N);
    for (t = 0; t < N; t++) {
        matrix[0][t] = first_row[t];
    }

    while (--M) {
        j = 0;
        row = readline();
        char *number = strtok(row, " ");
        while (number) {
            matrix[i][j++] = atoi(number);
            number = strtok(NULL, " ");
        }
        i++;
    }
    free(row);
    return N;
}


double **allocate_matrix(double **matrix, size_t side) {
    size_t i;

    if (!(matrix = realloc(matrix, sizeof(*matrix) * side))) {
        puts("Could not allocate memory.");
        exit(EXIT_FAILURE);
    }

    for (i = 0; i < side; i++) {
        matrix[i] = NULL;
        if (!(matrix[i] = realloc(matrix[i], sizeof(matrix[i]) * side))) {
            puts("Could not allocate memory.");
            exit(EXIT_FAILURE);
        }
    }
    return matrix;
}


void free_matrix(double **matrix) {
    size_t length = sizeof(matrix[0]) / sizeof(matrix[0][0]);
    while (length--) free(matrix[length]);
    free(matrix);
}


char *readline() {
    char *input = NULL;
    char tmpbuf[CHUNK];
    size_t inputlen = 0, tmplen = 0;

    do {
        fgets(tmpbuf, CHUNK, stdin);
        tmplen = strlen(tmpbuf);
        inputlen += tmplen;
        input = realloc(input, inputlen + 1);
        if (!input) {
            puts("Could not allocate memory.");
            exit(EXIT_FAILURE);
        }
        strcat(input, tmpbuf);
    } while (tmplen == CHUNK - 1 && tmpbuf[CHUNK - 2] != '\n');

    return input;
}

编辑以下是正确且有效的代码,万一有人感兴趣: https://codereview.stackexchange.com/questions/85769/reading-a-matrix-and-computing-the-determinant

4 个答案:

答案 0 :(得分:3)

您的代码存在许多问题。

首先,您没有正确初始化传递给realloc的指针。您必须确保它们都是有效的或NULL。这不是这种情况,而是在多个地方。

allocate_matrix函数中,当您重新分配到较小的大小时,您将失去指针。

free_matrix函数中,sizeof(matrix[0])表示sizeof(double*)不变。绝对不是你想要的。 sizeof(matrix[i])中的allocate_matrix也是如此。

parse_into中,您覆盖了matrix指针,但在调用后此更改将丢失,并且不会释放矩阵。

在同一个功能中,尽管多次调用free(row),您只需拨打readline一次。 readline将在每次调用时分配一个新缓冲区,因为函数中input设置为NULL。

再次在parse_into中,您永远不会释放first_row

答案 1 :(得分:2)

你知道你打电话给allocate_matrix 两次吗?进入main函数后,再次进入parse_into函数。问题是在parse_into中完成的分配只对本地副本matrix参数进行,此更改不会传递给调用函数。

这当然会导致内存泄漏,以及您读取的数据不会出现在您从main函数分配的矩阵中。

要解决此问题,您需要将matrix 通过引用(或至少将其模拟)传递给parse_into,或者提出另一种传递此新矩阵的方法回到main

答案 2 :(得分:2)

您在matrix

中为main()分配内存
matrix = allocate_matrix(matrix, MATRIX);
N = parse_into(matrix);

然后在parse_into()中,当你执行

时,你会丢弃该指针(及其内存)
matrix = allocate_matrix(matrix, N);

你也有潜在的错误。您通过将NULL指针传递给realloc()来分配内存。这会有效,但是当您free()内存时,您不会将指针重置为NULL。因此,如果您重新使用该指针,请在另一次迭代中说,realloc()将失败。

答案 3 :(得分:1)

另外,请注意:

if (!(matrix[i] = realloc(matrix[i], sizeof(matrix[i]) * side)))

错了。 sizeof(matrix [i])是指针的大小,但在这里你需要double的大小

相关问题