What is wrong passing a 2D array to a respective p

2019-08-11 21:31发布

问题:

I've been doing some matrix calculation in C for university the other day where I had a 5x5 matrix to begin with so I hard-coded it into the source. It was a 2D array of doubles like:

/**
 * This is the probability-matrix for reaching from any profile
 * to another by randomly selecting a friend from the friendlist.
 */
static const double F[5][5] = {
  /*           P    , F    , L    , A    , S    */
  /* Peter */ {0    , 0.5  , 0.5  , 0    , 0    },
  /* Franz */ {1.0  , 0    , 0    , 0    , 0    },
  /* Lisa  */ {0    , 1/3.0, 0    , 1/3.0, 1/3.0},
  /* Anna  */ {0    , 0    , 0    , 0    , 1    },
  /* Sepp  */ {0    , 0.5  , 0.5  , 0    , 0    }
};

I wanted my functions to not be fixed to operate on 5-by-5 matrices so I always pass the number of rows and/or cols to the function. This forces me not to use the double [][X] syntax because it can not be completely "variable" and instead use a double* as function parameter.

inline size_t matrix_get(int rows, int i, int j);

inline void matrix_print(double* m, int rows, int cols);

inline void matrix_copy(double* d, const double* s, int rows, int cols);

void matrix_multiply(
  int m, int n, int l,
  const double* a, const double* b, double* d);

But I always get this warning when calling a function that accepts double* when I passed double [5][5] instead.

fuenf_freunde.c:138:17: warning: incompatible pointer types passing 'double [5][5]' to parameter of
      type 'double *' [-Wincompatible-pointer-types]
  matrix_print( R, 5, 5);
                ^
fuenf_freunde.c:54:27: note: passing argument to parameter 'm' here
void matrix_print(double* m, int rows, int cols)
                          ^

Casting using (double*) F resolves the warning.

Now my questions are

  • am I wrong casting a 2D double array to a double pointer?
  • why is it working if its illegal?
  • what is the right way to pass an n-dimensional arbitrary size array to a function?

EDIT: This cleared a lot up for me: Accesing a 2D array using a single pointer

So I should just use double[x*y] instead of double[x][y] I think. But is it legal to cast double[] to double*?

回答1:

I contend that there is nothing wrong with what you do. Your code just lacks an explicit cast which would get rid of the warning, indicating that your assignment is intentional.

You can access a one dimensional array through a pointer to its elements, and recursively applied, it follows that n-dimensional matrices can be accessed through pointers to the atomic elements.

C guarantees a contiguous memory layout for them. This pattern is common. In fact passing arrays is hard or impossible to do differently, given the little information C stores with types (as opposed to, say, C#). So the matrix decays to a pointer to its first element (in your case to the first one dimensional array), which can safely be cast to an address of its first element, a double. They all share the same numerical address.

Typical concerns with pointer type casting are aliasing issues with modern optimizing compilers (a compiler can assume that you don't access memory through pointers of unrelated types except char*), but there is an explicit exemption in the standard draft 1570 which I have, par. 6.5.7, which I think is applicable here:

An object [that would be a double in your matrix, -ps] shall have its stored value accessed only by an lvalue expression that has one of the following types:

— a type compatible with the effective type of the object [that would be a dereferenced double pointer, -ps] [...]

— an aggregate [e.g. array, -ps] [...] type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union) [that would be your matrix variable, containing, eventually, doubles, -ps]

[...]



标签: c clang c99