数组C++:你能解释一下这行代码在做什么吗?

arrays in C++: can you explain what this line of code is doing?

本文关键字:代码 什么 一下 C++ 能解释 数组      更新时间:2023-10-16

我需要修改一些C++代码,但由于我对这门语言相对较新,所以我很难理解一些表达式。

我有一个功能

void func(double m[2][12],double n[2][3])

从像这样的其他函数内部调用

double A[12];
double B[6];
(...)
func( (double (*)[12])A, (double (*)[3])B )

最后一行代码是将 1D 数组转换为 2D 数组,但那里到底发生了什么?我可以使用相同的技术将一维数组转换为二维数组吗,像这样?

double A[12];
double B[6];
(double (*)[12])A[0][5] = 5;

正在发生的事情正是您提到的 - 调用者正在将一维数组转换为 为了将它们传递给 func() ,它有两个指向 2D 数组的指针参数。 由于 C 中的 2D 数组只是"数组的数组"(即不涉及指针(,因此这种转换当然是可能的。 例如,这个一维数组:

int oneDimensionalArray[] = { 0, 1, 2, 3 };

和这个 2D 数组:

int twoDimensionalArray[] = { { 0, 1 }, 
                              { 2, 3 } };

具有完全相同的内存布局。 您可以通过使用疯狂的城镇转换操作来强制类型进行匹配,就像您问题中的操作一样。

至于你的第二个问题,是的,你可以这样做,但你需要另外一组括号:

((double (*)[12])A)[0][5] = 5;

不过,我不建议在编写这种疯狂的事情的代码时。 该计划从何而来?

转换不是从 1D 到 2D 数组,而是指向静态 1D 数组的指针!

double m1[12];

表示类型为">12 个双精度的静态数组"的变量 M1

double m2[2][12];

表示隐式推断类型">2 个元素的静态数组"类型为"12 双精度静态数组"的变量 M2当静态数组用作函数参数时,它们将退化为数组元素类型的指针。因此,对于数组 m1,上面我们可以使用以下任何函数

f11(double arg[12]) {}  
f12(double * arg) {}

两者都可以使用任何指向 double 的指针或任何双精度元素数组来调用,例如:

double a=0.0;
double b[10];
f11(&a); f11(b);
f12(&b); f12(b);

类似地,对于数组 m2(上图(,单个元素的类型是"double[12]"。因此,我们可以使用以下任何函数:

f21(double arg[2][12]) {}  
f22(double * arg[12]) {}
可以使用指向"12

个双精度数组"的任何指针或任何类型为">12 个双精度数组"的元素数组调用,例如:

double c[12];
double d[6][12];
f21((double (*)[12])c); f21(d);   
f22((double (*)[12])c); f22(d);  

现在对于您的代码,该函数实际上void func(double m[2][12],double n[2][3])需要一个指向">12 个双精度的静态数组"的指针和一个指向">3 个双精度的静态数组"的指针。因此,您看到的呼叫

double A[12];
double B[6];
func( (double (*)[12])A, (double (*)[3])B )
实际上将 A(退化为指针到双精度(转换为指向"12 个双精度的静态数组"的指针

,并将 B(也退化为指针到双精度(转换为指向">3 个双精度的静态数组"的指针由于所有给定的数组都使用双精度数组,并且静态数组在内存中按顺序表示,因此此类转换可能不会导致逻辑错误。

声明

void func(double m[2][12],double n[2][3])

相当于

void func(double (*m)[12],double (*n)[3])

即第一个数组维度无关紧要。顶级数组类型衰减为指针类型,从而将 2D 数组参数声明转换为指向 1D 数组参数声明的指针。

可以使用这些参数调用此函数

double A[12];
double B[3]; /* note 3 instead of 6 */

正确的方法很简单

func(&A, &B);

请注意,不需要强制转换,只需应用&运算符,因为AB具有正确的类型(本例中为 double[12]double[3](。在这种情况下,在函数内部,人们只能访问m[0][i]n[0][i],而不能访问m[1][i]n[1][i],因为它们不存在。

在您的示例中,代码的作者采取了一些非常奇怪的步骤。

首先,显然作者没有意识到第一个参数可以表示为&A,不需要强制转换,因为A是用正确的类型声明的。

其次,完全不清楚为什么B被声明为大小6数组,当函数需要大小为3的数组时。为了将此参数强制到该函数中,确实需要显式强制转换。

两个参数的传递方式只是错误代码的一个示例。


至于将一维数组转换为二维数组...请记住,在 C 和 C++ 中,任何 T 类型的对象都可以解释为具有 1 个类型 T 元素的一维数组。只需要将&运算符应用于对象。例如

int i = 0;
(&i)[0] = 5; /* access `&i` as `int[1]` array */
assert(i == 5);

如果所讨论的对象本身是一个数组,也可以做同样的事情。例如,可以将 1D 数组作为第一个大小等于 1 的 2D 数组进行访问

int a[10] = { 0 };
(&a)[0][8] = 42; /* access `&a` as an `int[1][10]` array */
assert(a[8] == 42);
这正是

您的示例中发生的情况,只是正确的方法是将 & 运算符应用于原始对象。代码的作者使用强制转换实现相同的效果。演员不是正确的方法。它不能保证有效,它只是碰巧在实践中具有相同的效果。