我写了一个简单的程序来读取任何方阵并计算其行列式。然而,根据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会议期间结果是错误的!如何使用相同的输入输出330
和0
? 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
答案 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的大小