C 将2D数组传递给相应的指针参数有什么错误?

C 将2D数组传递给相应的指针参数有什么错误?,c,clang,c99,C,Clang,C99,前几天,我在大学里用C语言做了一些矩阵计算,我从一个5x5矩阵开始,所以我把它硬编码到源代码中。这是一个二维双打阵列,如: /** * 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

前几天,我在大学里用C语言做了一些矩阵计算,我从一个5x5矩阵开始,所以我把它硬编码到源代码中。这是一个二维双打阵列,如:

/**
 * 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    }
};
我不希望我的函数固定在5乘5的矩阵上,所以我总是将行数和/或列数传递给函数。这迫使我不使用
double[][X]
语法,因为它不能完全是“变量”,而是使用
double*
作为函数参数

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);
但是当调用一个函数时,我总是得到这个警告,该函数在我传递
double[5][5]
时接受
double*

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)
                          ^
使用
(双*)F
进行强制转换可解决警告问题

现在我的问题是

  • 将2D双数组强制转换为双指针是否错误
  • 如果它是非法的,为什么它会起作用
  • 将n维任意大小的数组传递给函数的正确方法是什么
编辑:这为我澄清了很多:


所以我应该使用
double[x*y]
而不是
double[x][y]
。但是将
double[]
转换为
double*
合法吗?

我认为你所做的没有错。您的代码只是缺少一个可以消除警告的显式强制转换,这表明您的赋值是有意的

您可以通过指向其元素的指针访问一维数组,并递归应用,因此可以通过指向原子元素的指针访问n维矩阵

C保证为它们提供连续的内存布局。这种模式很常见。事实上,考虑到C存储的类型信息很少(与C#相反),传递数组很难或不可能有不同的做法。因此,矩阵衰减为指向其第一个元素的指针(在您的例子中是指向第一个一维数组),该指针可以安全地转换为其第一个元素的地址,即double。它们都共享相同的数字地址

指针型铸造的典型关注点是与现代优化编译器混淆的问题(编译器可以假设您不通过不相关类型的指针访问char *以外的内存),但在标准草案1570中,我有一个明确的豁免,即PAR。6.5.7,我认为适用于此:

一个对象[在你的矩阵中是双精度的,-ps]的存储值只能由左值访问 具有以下类型之一的表达式:

-与对象的有效类型兼容的类型[即取消引用的双指针,-ps] [……]

-聚合[例如数组,-ps] […]类型,其中包括上述类型之一 成员(递归地包括子集合的成员或 包含并集)[这将是您的矩阵变量,最终包含双精度,-ps]

[……]


你怎么会认为
double[5][5]
double*
是兼容的?如果有什么问题的话,最常见的错误就是认为一个或多个数组等于指向指针()的指针。类型
double[5][5]
相当于
double(*)[]
@JoachimPileborg,就像
double[5]
double*
兼容一样。。。至少,clang没有对此抱怨。既然
double[5][5]
在内存中显示为
double[25]
问问自己;指向双精度的指针是否与指向双精度[N]的指针相同?同样,这种思维方式会让你在C语言中遇到麻烦:(因为我的代码按预期工作)为什么编译器会抱怨?@EdS。假设我要从双数组中释放第一块与双指针大小匹配的内存,它的值不太可能与数组的实际内存位置相同吗我想我在什么地方读到过,2D数组在C/C++中只是一个一维数组,编译器会自动将索引转换为线性索引。@ThePlamagneticCroissant谢谢,我很理解。但是什么让它在这种特殊情况下起作用?如果
double[][X]
(double*)[X]
相同,那么
(double*)数据
怎么可能与
&数据[0][0]
具有相同的值?(根据它们指向的内存位置)