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

时间:2011-04-05 17:14:36

标签: c++ arrays

我需要修改一些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;

3 个答案:

答案 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具有适当的类型(Bdouble[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);

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