【问题标题】:Pointer to 2D Array(why does it work)指向二维数组的指针(为什么有效)
【发布时间】:2017-04-22 15:45:24
【问题描述】:

我有以下功能(我想打印给定行中的所有元素)

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" ?不应该传递地址吗?为什么我可以使用间接运算符?

【问题讨论】:

  • 不太清楚问题出在哪里。您正在传递地址并在方法内移动指针
  • 代码有效,问题是我不明白为什么(为什么我可以把它称为 print_row(i, 3, *j) - with *j)。
  • auto t1 = j; // int (*t1)[3]auto t2 = *j; // int *t2
  • @flatmouse 为什么*jint**j 应与 *(&amp;j[0]) 相同,后者应为您提供 j[0]
  • @NathanOliver *j 确实给了你j[0],这是一个int[3],然后衰减为int*

标签: c++ arrays pointers multidimensional-array


【解决方案1】:
int j[3][3] = 
{{1,2,3},
{4,5,6},
{7,8,9}}; // 2d array

auto t1 = j; // int (*t1)[3]
auto t2 = *j; // int *t2

所以发生的事情是*j 产生j[0],这是一个int[3],然后衰减为int*

【讨论】:

    【解决方案2】:

    j 实际上是一个数组数组。因此,*j 是一个由三个整数组成的数组,当用作右值时,它会衰减为指向其第一个元素的指针,换句话说,它会衰减为 &j[0][0]。

    然后在printrow 中计算每个子数组的第一个元素的起始地址 - 这是不太好的部分,我稍后再讨论。然后你正确地使用*(p+i) 等效的p[i] 来访问子数组的每个元素。


    答案的其余部分是我对严格阅读C标准的解释

    我说过计算每个子数组的起始地址是不太好的部分。它之所以有效,是因为我们都知道大小为 NxM 的 2D 数组在内存中具有与大小为 N*M 的线性数组相同的表示,并且我们为这些表示别名。但是如果我们严格遵守标准,作为一个 int 指针,&amp;p[i][j] 指向一个由三个元素组成的数组的第一个元素。因此,当您添加行的大小时,如果您稍后取消引用此地址,则指向数组的末尾会导致未定义的行为。当然,它适用于所有常见的编译器,但在old question of mine 上,@HansPassant 给了我一个关于能够强制控制数组大小的实验编译器的参考。这些编译器可以检测到超出数组末尾的访问并引发运行时错误……但它会破坏很多现有代码!

    要严格遵守标准,您应该使用指向 3 个整数数组的指针。它需要使用可变长度数组,这是一个可选功能,但完全符合支持它的系统的标准。或者,您可以深入到 2D 数组的 byte 表示,获取其初始地址,然后从那里计算 作为字节地址每个子数组的起点。这是很多沸腾板地址计算,但它完全遵守@#!%$ 严格的别名规则...

    TL/DR:此代码适用于所有常见的编译器,并且可能适用于它们的许多未来版本,但严格解释标准是不正确的。

    【讨论】:

      【解决方案3】:

      您的代码有效,因为*j 是一个与jj[0] 具有相同值的指针。这种行为是由编译器处理二维数组的机制引起的。

      当你声明二维数组时:

      int j[3][3]={{1,2,3},
                   {4,5,6},
                   {7,8,9}};
      

      编译器实际上将所有值按顺序放入内存中,因此以下声明将具有相同的占用空间:

      int j[9]={1,2,3,4,5,6,7,8,9};
      

      所以在您的情况下,指针 j*jj[0] 只是指向内存中的同一个位置。

      【讨论】:

        【解决方案4】:

        内存不是多维的,所以即使它是一个二维数组,它的数据也会按顺序放置,所以如果你得到一个指向该数组的指针——这隐含地指向它的第一个元素—— - 并开始顺序读取元素,您将遍历此二维数组的所有元素,从前一个元素的最后一个元素之后的后续行中读取元素。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-06-11
          • 2012-01-26
          相关资源
          最近更新 更多