【问题标题】:why does this pointer arithmetic on a 2D array work?为什么二维数组上的这个指针算法有效?
【发布时间】:2013-12-11 16:13:26
【问题描述】:

我写了以下代码:

#include <iostream>
using namespace std;

int main()
{
    int a[10][10];
    for (int i = 0; i < 10; i++)
        for (int j = 0; j < 10; j++)
            a[i][j] = i * j;
    cout << *(*(a + 3) + 4) << endl;
    return 0;
}

我期待它打印一些垃圾数据或分段错误。我得到的是 12。我在 c 和 c++ 中都对其进行了测试(分别使用 gcc 和 g++),尽管我还没有测试过,但我在 VS 上的效果是一样的。为什么这会起作用,是否有关于这种行为的官方文档?

【问题讨论】:

  • 为什么它不能工作?
  • 提示:a[b] == *(a+b)
  • @KirilKirov 我认为人们可能认为它不应该以这种方式工作的一个原因是人们可能认为将 3 添加到指针会将其指向的地址移动 3 个字节。要回答 OP 的问题,将 3 添加到指针会将其指向的地址移动 3 * sizeof(T) 字节,其中 T 是指针所指的对象类型。这就是为什么保持指针类型正确很重要的原因,以及为什么不只是一个名为pointer 的通用类型,或者为什么我们不只对所有内容都使用void*
  • @Andrey - 是的,这是我的第一个想法,但后来我在标题中看到了“指针算术”,这是确切的术语,所以我决定让 OP 熟悉这一点。无论如何:)

标签: c++ c multidimensional-array pointer-arithmetic


【解决方案1】:

*(a + b)=a[b]你取a的地址,移动b,取对应地址的值

所以*(*(a + 3) + 4)意思是*(a[3]+4),意思是a[3][4]=12

【讨论】:

    【解决方案2】:

    声明

    int a[m][n];
    

    表示m数组的数组,其中每个这样的内部数组的大小为n

    我记得最后一个索引变化最快。

    在表达式(a + 3) 中,对外部数组的a 引用衰减为指向该外部数组项的指针。 IE。指向大小n 数组的指针。 + 3 然后将内部数组的 3 倍字节大小添加到 a-as-pointer 的地址。

    取消引用会为您提供指向int 的指针。

    向其中添加 4 会使您在内部数组中获得 4 个位置。

    这种方案的美妙之处在于它也适用于“锯齿状数组”,即指针数组,因为它们的类型不同。

    非常可悲的是它不适用于 C++ 派生类,因为 Derived 的数组衰减为指向 Derived 的指针,然后可以隐式转换为指向 Base 的指针,这当索引产生正式的未定义行为(Derived 的大小可以大于Base 的大小)。

    【讨论】:

    • 二维数组不就是一段很长的连续内存吗?就像 remyabel 解释的那样?
    • @elyashiv:是的。不过,该标准提出的要求并不完全明显。连续性要求间接通过大小要求来实现,即在 C++11 §5.3.3/2 中,您会发现“当 [sizeof is] 应用于数组时,结果是数组中的字节总数。这意味着n 个元素的数组的大小是元素大小的 n 倍。”这反过来又要求多维数组连续存储,没有内部填充。
    【解决方案3】:

    详细说明请参见question

    二维数组 ([][], not **) 在内存中是连续的,因此您可以使用以下公式访问元素:

    *((int *)array + X * NUMBER_OF_COLUMNS + Y);
    

    std::cout << *((int *)a + 3 * 10 + 4);
    

    【讨论】:

    • 我知道这一点。问题是 - 我没有乘以十。
    • @elyashiv 10 是列数,这就是在我提供的示例中需要乘以 10 的原因。 *(*(a + 3) + 4) 没有必要,因为您正在对 a 执行指针运算。
    • 我想你的意思是*(array + Y * NUMBER_OF_COLUMNS + X),因为它需要NUMBER_OF_COLUMNS 列(“X”)才能组成一行(“Y”)
    【解决方案4】:

    如果您想要一个简单的答案,请使用 typedefs 构建复杂类型

    意思是:

    int a[10][10];
    

    将是:

    typedef int a10[10]; //a10 is array of 10 ints 
    a10 a[10]; //a is array of 10 a10s
    

    现在了解尺寸和位置:

    sizeof(a) = 10 * 10 * sizeof int
    sizeof(a[0]) = is  10 * sizeof int
    a+1 is equal to &a[1]
    

    当你将一个指针增加 3 时,它的意思是按类型的 sizeof 增加。

    address of a[1] == address of a[0] + sizeof(a[0])
    

    因此:

    *(*(a + 3) + 4) == a[3][4] 
    

    【讨论】:

      【解决方案5】:

      您可以使用 *(arr + index) 或 arr[index] 对数组进行索引。它们在语义上不同,但在功能上相同。

      有关更多信息,请参阅此 Stack Overflow 讨论。

      Difference Between *(Pointer + Index) and Pointer[]

      【讨论】:

        【解决方案6】:

        你得到的输出是12,它是绝对正确的。 你为数组的每个元素做了a[i][j] = i*j ;。现在您打印*( *(a + 3) + 4),它与a[3][4] 相同。正如您所做的a[i][j] = i*j,您现在拥有a[3][4] = 3*4 = 12。所以它会打印12

        【讨论】:

        • 我认为您正在尝试说正确的话。但是,您的答案格式不正确,因此难以阅读和理解。此外,已经有 5 个很好的答案,真的值得吗? :-)
        猜你喜欢
        • 2017-04-22
        • 1970-01-01
        • 2021-11-13
        • 2020-07-31
        • 1970-01-01
        • 2019-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多