我需要修改一些C ++代码,但由于我对该语言比较陌生,所以我无法理解某些表达式。
我有一个功能
void func(double m[2][12],double n[2][3])
从其他函数内部调用
double A[12];
double B[6];
(...)
func( (double (*)[12])A, (double (*)[3])B )
最后一行代码是将一维数组转换为2D数组,但究竟发生了什么?我是否可以使用相同的技术将1D数组转换为2D,如下所示?:
double A[12];
double B[6];
(double (*)[12])A[0][5] = 5;
答案 0 :(得分:7)
正在发生的事情就是你提到的 - 调用者正在将1维数组转换为将它们传递给func()
,它有两个指针指向2D数组的参数。由于C中的2D数组只是“数组数组”(即没有涉及指针),因此这种转换当然是可能的。例如,这个1D数组:
int oneDimensionalArray[] = { 0, 1, 2, 3 };
和这个2D数组:
int twoDimensionalArray[] = { { 0, 1 },
{ 2, 3 } };
具有完全相同的内存布局。您可以通过使用疯狂城镇投射操作(例如您的问题中的那个)将类型强制转换为匹配。
关于你的第二个问题,是的,你可以这样做,但你还需要一套括号:
((double (*)[12])A)[0][5] = 5;
但是,我不建议用这种疯狂的东西编写代码。该计划来自哪里?
答案 1 :(得分:1)
转换不是从1D到2D数组,而是指向静态1D数组的指针!
double m1[12];
表示变量m1的类型为' 12个双精度的静态数组'
double m2[2][12];
表示变量m2的隐式推断类型' 2个元素的静态数组,类型为“12个双倍的静态数组”' 当静态数组用作函数参数时,它们将退化为数组元素类型的指针。 因此,对于数组m1,我们可以使用以下任何函数
f11(double arg[12]) {}
f12(double * arg) {}
可以使用任何指向double或任何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(退化为指向double的指针)转换为指向' 12个双打的静态数组'的指针,并将B(也是退化为指向double的指针)转换为指向'<的指针em> 3个双打的静态数组' 因为所有给定的数组都使用双精度数据,静态数组在内存中按顺序表示,这样的强制转换可能不会导致逻辑错误。
答案 2 :(得分:0)
声明
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);
注意,由于&
和A
具有适当的类型(B
和double[12]
,因此不需要强制转换,只需double[3]
运算符的应用程序在这个例子中)。在这种情况下,在函数内部只能访问m[0][i]
和n[0][i]
,而不能访问m[1][i]
或n[1][i]
,因为这些不存在。
在您的示例中,代码的作者采取了一些真正奇怪的步骤。
首先,显然作者没有意识到第一个参数可以表示为&A
,不需要强制转换,因为A
被声明为正确的类型。
其次,当函数需要一个大小为B
的数组时,为什么6
被声明为大小为3
的数组,这是完全不清楚的。为了强制该参数进入该函数,确实需要显式转换。
传递两个参数的方式只是坏代码的一个例子。
至于将1D数组转换为2D数组...请记住,在C和C ++中,类型T
的任何对象都可以解释为1D数组,其中1个元素类型为T
。只需要将&
运算符应用于对象。例如
int i = 0;
(&i)[0] = 5; /* access `&i` as `int[1]` array */
assert(i == 5);
如果有问题的对象本身就是一个数组,那么可以做同样的事情。例如,1D阵列可以作为2D阵列访问,第一个大小等于1
int a[10] = { 0 };
(&a)[0][8] = 42; /* access `&a` as an `int[1][10]` array */
assert(a[8] == 42);
这正是您的示例中发生的情况,除了正确的方法是将&
运算符应用于原始对象。代码的作者使用强制转换实现了相同的效果。施放不是正确的方法。它不能保证工作,它恰好在实践中具有相同的效果。