0

I have a function which returns the inverse matrix like this:

double** inverse(double (**data)) {

    double result[2][2];
    result[0][0] =  data[1][1] /  (data[0][0] * data[1][1] - data[0][1] * data[1][0]);
    result[0][1] = -data[0][1] / (data[0][0] * data[1][1] - data[0][1] * data[1][0]);
    result[1][0] = -data[1][0] / (data[0][0] * data[1][1] - data[0][1] * data[1][0]);
    result[1][1] = data[0][0] / (data[0][0] * data[1][1] - data[0][1] * data[1][0]);

    return result;
}

And I have checked values in result, they are right. Then:

    double** s = inverse(gama[FreIdx]);

    printf("%f\n", s[0][0]);

and I got Exception. An access violation occurred while reading location 0x0...... I am not very familiar with C. Can anyone tell me what happened?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
马慧超
  • 183
  • 1
  • 10
  • 1
    Arrays are not pointers, and returning a pointer to a local array is UB. – Martin James Jul 22 '17 at 11:16
  • `result` is local. – Yunnosch Jul 22 '17 at 11:16
  • 1
    If you enable compiler warnings/errors, this won't even compile. http://ideone.com/DTSSwy – Oliver Charlesworth Jul 22 '17 at 11:17
  • You have to ignore a lot of compiler warnings to get this to compile. That it then crashes is no surprise. Returning pointers to local variables is a no-no; treating a 2D array of `double` as a `double **` is a no-no. Combining the type mismatch with the undefined behaviour means a crash is plausible. Be grateful; it could have been so much worse than just crashing. – Jonathan Leffler Jul 22 '17 at 17:52
  • @ALL thanks guy I know where I am wrong,Thanks very much. – 马慧超 Jul 24 '17 at 00:50

2 Answers2

1

You are creating a matrix inside inverse, statically, which means it will reside inside the stack frame of that function call. Then you return the address of that matrix, but as soon as you return the function, the stack frame of it can be overwritten.
You need to dynamically allocate the matrix, and remember to free it as soon as it is not needed.

double** inverse(double data[][2]) {

    double **result = malloc(sizeof(double*) * 2);
    result[0] = malloc(sizeof(double) * 2);
    result[1] = malloc(sizeof(double) * 2);

    result[0][0] =  data[1][1] /  (data[0][0] * data[1][1] - data[0][1] * data[1][0]);
    result[0][1] = -data[0][1] / (data[0][0] * data[1][1] - data[0][1] * data[1][0]);
    result[1][0] = -data[1][0] / (data[0][0] * data[1][1] - data[0][1] * data[1][0]);
    result[1][1] = data[0][0] / (data[0][0] * data[1][1] - data[0][1] * data[1][0]);

    return result;
}

And freeing it:

double **inv = inverse(mat);
free(inv[0]);
free(inv[0]);
free(inv);

Note: It is best to create a destructor function that will take care of freeing the inner arrays and the outer one. And it is also good practice to put NULL in inv (that you just freed), to catch potential usage after free.

Yuval Ben-Arie
  • 1,280
  • 9
  • 14
1
  1. returning a double[2][2] from double** function invokes undefined behaviour (see here for details).

    Anything might happen from then on.

    Take your compiler's warnings seriously.

  2. Even worse, result lives on the inverse() function's stack and is dead and gone the moment the function had returned.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
alk
  • 69,737
  • 10
  • 105
  • 255