C: free() 无效指针;无需更改地址
C: free() invalid pointer; without changing address
我正在使用 C(不是 C++)并收到以下错误:
Error in './c_rk4': free(): invalid pointer: 0x0000000000a911c0
我能够将错误追溯到第 (1) 和 (2) 行。如果我注释掉我标记的行,则不会发生 (1) 中的错误。所有其他 free()
用法都不会产生错误,如果我用 free()
.
注释掉所有行,程序将按预期运行
我检查了像 printf("%p\n", y_n);
这样的行 y_n
的地址在 malloc()
之后和 free()
之前是相同的(并且正是错误消息中的地址) .
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
void odesolver_rk4 (void (*)(double, _Complex double *, _Complex double **),
int, double,
int, _Complex double *, _Complex double ***);
void testfunc (double, _Complex double *, _Complex double **);
int main (int argc, char *argv[argc]) {
const int t_num = 300;
const int y_num = 2;
_Complex double **y_res;
y_res = malloc(t_num*sizeof(_Complex double *));
for (int i = 0; i < t_num; i++)
y_res[i] = malloc(y_num*sizeof(_Complex double));
odesolver_rk4(testfunc, t_num, 20.0, y_num, (_Complex double []){1.0, 0.0}, &y_res);
for (int i = 0; i < t_num; i++) {
for (int j = 0; j <= y_num; j++) {
printf("%f %f ", creal(y_res[i][j]), cimag(y_res[i][j]));
}
printf("\n");
}
for (int i = 0; i < t_num; i++)
free(y_res[i]); // error (2)
free(y_res);
return 0;
}
void odesolver_rk4 (void (*func)(double, _Complex double *, _Complex double **),
int t_num, double t_end,
int y_num, _Complex double *y_start, _Complex double ***y_res) {
double t_step = t_end/t_num;
double t_n = 0;
_Complex double *y_n, *y_A, *y_B, *y_C;
_Complex double *dy_n, *dy_A, *dy_B, *dy_C;
y_n = malloc(y_num*sizeof(_Complex double));
y_A = malloc(y_num*sizeof(_Complex double));
y_B = malloc(y_num*sizeof(_Complex double));
y_C = malloc(y_num*sizeof(_Complex double));
dy_n = malloc(y_num*sizeof(_Complex double));
dy_A = malloc(y_num*sizeof(_Complex double));
dy_B = malloc(y_num*sizeof(_Complex double));
dy_C = malloc(y_num*sizeof(_Complex double));
for (int j = 0; j < y_num; j++)
y_n[j] = y_start[j];
(*y_res)[0][0] = t_n;
for (int j = 0; j < y_num; j++)
(*y_res)[0][j + 1] = y_start[j];
for (int i = 1; i < t_num; i++) {
func(t_n, y_n, &dy_n);
for (int j = 0; j < y_num; j++)
y_A[j] = y_n[j] + dy_n[j]*t_step/2;
func(t_n + t_step/2, y_A, &dy_A);
for (int j = 0; j < y_num; j++)
y_B[j] = y_n[j] + dy_A[j]*t_step/2;
func(t_n + t_step/2, y_B, &dy_B);
for (int j = 0; j < y_num; j++)
y_C[j] = y_n[j] + dy_B[j]*t_step;
func(t_n + t_step, y_C, &dy_C);
for (int j = 0; j < y_num; j++) {
y_n[j] += t_step/6*(dy_n[j] + 2*(dy_A[j] + dy_B[j]) + dy_C[j]);
(*y_res)[i][0] = t_n;
(*y_res)[i][j + 1] = y_n[j]; // something goes wrong here for (1)
}
t_n += t_step;
}
free(y_n); // error (1)
free(y_A);
free(y_B);
free(y_C);
free(dy_n);
free(dy_A);
free(dy_B);
free(dy_C);
}
void testfunc (double t, _Complex double *y, _Complex double **dy) {
(*dy)[0] = -y[1];
(*dy)[1] = y[0];
}
问题是这个循环:
for (int j = 0; j < y_num; j++)
这行代码:
(*y_res)[i][j + 1] = y_n[j]
要么你的循环需要 j < y_num - 1
,要么你的表达式应该使用 [j]
。否则,您将越过 y_res
数组的末尾。当您这样做时,您将覆盖 y_n
分配的 malloc header,这就是为什么 free()
后来抱怨它是一个无效指针的原因。
顺便说一句,valgrind 是一个非常好的工具,可以用来发现这类问题。
评论中还推荐了 AddressSanitizer:
我正在使用 C(不是 C++)并收到以下错误:
Error in './c_rk4': free(): invalid pointer: 0x0000000000a911c0
我能够将错误追溯到第 (1) 和 (2) 行。如果我注释掉我标记的行,则不会发生 (1) 中的错误。所有其他 free()
用法都不会产生错误,如果我用 free()
.
我检查了像 printf("%p\n", y_n);
这样的行 y_n
的地址在 malloc()
之后和 free()
之前是相同的(并且正是错误消息中的地址) .
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
void odesolver_rk4 (void (*)(double, _Complex double *, _Complex double **),
int, double,
int, _Complex double *, _Complex double ***);
void testfunc (double, _Complex double *, _Complex double **);
int main (int argc, char *argv[argc]) {
const int t_num = 300;
const int y_num = 2;
_Complex double **y_res;
y_res = malloc(t_num*sizeof(_Complex double *));
for (int i = 0; i < t_num; i++)
y_res[i] = malloc(y_num*sizeof(_Complex double));
odesolver_rk4(testfunc, t_num, 20.0, y_num, (_Complex double []){1.0, 0.0}, &y_res);
for (int i = 0; i < t_num; i++) {
for (int j = 0; j <= y_num; j++) {
printf("%f %f ", creal(y_res[i][j]), cimag(y_res[i][j]));
}
printf("\n");
}
for (int i = 0; i < t_num; i++)
free(y_res[i]); // error (2)
free(y_res);
return 0;
}
void odesolver_rk4 (void (*func)(double, _Complex double *, _Complex double **),
int t_num, double t_end,
int y_num, _Complex double *y_start, _Complex double ***y_res) {
double t_step = t_end/t_num;
double t_n = 0;
_Complex double *y_n, *y_A, *y_B, *y_C;
_Complex double *dy_n, *dy_A, *dy_B, *dy_C;
y_n = malloc(y_num*sizeof(_Complex double));
y_A = malloc(y_num*sizeof(_Complex double));
y_B = malloc(y_num*sizeof(_Complex double));
y_C = malloc(y_num*sizeof(_Complex double));
dy_n = malloc(y_num*sizeof(_Complex double));
dy_A = malloc(y_num*sizeof(_Complex double));
dy_B = malloc(y_num*sizeof(_Complex double));
dy_C = malloc(y_num*sizeof(_Complex double));
for (int j = 0; j < y_num; j++)
y_n[j] = y_start[j];
(*y_res)[0][0] = t_n;
for (int j = 0; j < y_num; j++)
(*y_res)[0][j + 1] = y_start[j];
for (int i = 1; i < t_num; i++) {
func(t_n, y_n, &dy_n);
for (int j = 0; j < y_num; j++)
y_A[j] = y_n[j] + dy_n[j]*t_step/2;
func(t_n + t_step/2, y_A, &dy_A);
for (int j = 0; j < y_num; j++)
y_B[j] = y_n[j] + dy_A[j]*t_step/2;
func(t_n + t_step/2, y_B, &dy_B);
for (int j = 0; j < y_num; j++)
y_C[j] = y_n[j] + dy_B[j]*t_step;
func(t_n + t_step, y_C, &dy_C);
for (int j = 0; j < y_num; j++) {
y_n[j] += t_step/6*(dy_n[j] + 2*(dy_A[j] + dy_B[j]) + dy_C[j]);
(*y_res)[i][0] = t_n;
(*y_res)[i][j + 1] = y_n[j]; // something goes wrong here for (1)
}
t_n += t_step;
}
free(y_n); // error (1)
free(y_A);
free(y_B);
free(y_C);
free(dy_n);
free(dy_A);
free(dy_B);
free(dy_C);
}
void testfunc (double t, _Complex double *y, _Complex double **dy) {
(*dy)[0] = -y[1];
(*dy)[1] = y[0];
}
问题是这个循环:
for (int j = 0; j < y_num; j++)
这行代码:
(*y_res)[i][j + 1] = y_n[j]
要么你的循环需要 j < y_num - 1
,要么你的表达式应该使用 [j]
。否则,您将越过 y_res
数组的末尾。当您这样做时,您将覆盖 y_n
分配的 malloc header,这就是为什么 free()
后来抱怨它是一个无效指针的原因。
顺便说一句,valgrind 是一个非常好的工具,可以用来发现这类问题。
评论中还推荐了 AddressSanitizer: