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 是一个非常好的工具,可以用来发现这类问题。

http://valgrind.org

评论中还推荐了 AddressSanitizer:

http://clang.llvm.org/docs/AddressSanitizer.html