我有以下功能(我想打印给定行中的所有元素)
void print_row(int j, int row_dimension, int *p)
{
p = p + (j * row_dimension);
for(int i = 0; i< row_dimension; i++)
cout<<*(p+i)<< " ";
}
创建一个数组
int j[3][3]={{1,2,3},
{4,5,6},
{7,8,9} };
我不明白的是为什么我可以通过以下方式调用该函数:
print_row(i, 3, *j);
为什么可以给我一个参数“ * j”?地址不应该通过吗?为什么要使用间接运算符?
j
实际上是一个数组数组。这样,它*j
是一个由三个整数组成的数组,当用作右值时,它将衰减为指向其第一个元素的指针,换句话说,它将衰减为&j [0] [0]。
然后,在printrow
计算每个子数组的第一个元素的起始地址时-这是不太好的部分,我稍后再讲。然后,您可以正确使用*(p+i)
等价的p[i]
来访问子数组的每个元素。
答案的其余部分是我对C标准的严格阅读的解释
我说过,计算每个子数组的起始地址不是那么好。之所以起作用,是因为我们都知道大小为NxM的2D数组在内存中的表示形式与大小为N * M的线性数组相同,因此我们将这些表示形式作为别名。但是,如果我们严格遵守标准,则作为int指针,它&p[i][j]
指向三个元素的数组中的第一个元素。这样,当您增加行的大小时,您将指向数组的末尾,如果您稍后取消引用该地址,则会导致未定义的行为。当然,它可以与所有常见的编译器一起使用,但是这是我的一个老问题,@ HansPassant给了我有关能够对数组大小执行控制的实验性编译器的参考。这些编译器可以检测到数组末尾的访问,并引发运行时错误……但是这会破坏很多现有代码!
为了严格符合标准,应使用一个指向3个整数的数组的指针。它要求使用可变长度数组,这是一项可选功能,但完全符合支持该功能的系统的标准。或者,您可以转到2D数组的字节表示形式,获取其初始地址,然后从那里计算每个子数组的起点作为字节地址。这是很多沸腾的地址计算,但它完全遵守@#!%$严格的别名规则...
TL / DR:此代码可用于所有常见的编译器,并且可能会与它们的许多将来版本一起使用,但是严格解释该标准并不正确。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句