【问题标题】:2Dimensional Array Pointer manipulation in C++C++ 中的二维数组指针操作
【发布时间】:2012-03-23 21:29:06
【问题描述】:
int main(){
    int a[10][10];
    int **ptr =(int **)a;
    cout<<a<<endl<<ptr<<endl;
    cout<<*a<<endl<<*ptr<<endl;
    return 0;
}

这段代码在我电脑上的输出是

0021FC20
0021FC20
0021FC20
CCCCCCCC

为什么“a”等于“*a”? 为什么 *a 不等于 *ptr?

【问题讨论】:

标签: c++ pointers multidimensional-array


【解决方案1】:

2D 数组的机制实际上比它们最初看起来要容易,但通常教得不好。尽管如此,快速破译事物确实需要大量经验,即使是经验丰富的开发人员有时也不得不停下来思考片刻(或两片)。基本上,当您看到诸如 int a[5][10] 之类的 2D 数组(我将数组的大小更改为 5 以简化事情)时,您需要停止将其视为 2D。把它想象成一维的。第一个下标指定此一维数组中的元素数量,就像任何其他一维数组一样。当您对数组进行索引时,例如 a[3],您将访问索引 3 处的对象。这与任何其他数组没有什么不同。假设“a”是这样定义的:

// Note: The size of the array, 5, can be omitted
int a[5] = {5, 10, 15, 20, 25};

然后下标产生这个:

a[0] = 5
a[1] = 10
a[2] = 15
a[3] = 20
a[4] = 25

这很容易,大多数人都能做到。但如果你现在这样做:

// Note: Like above, the size of the array, 5, can be omitted
int a[5][10] = {{  5,  10,  15,  20,  25,  30,  35,  40,  45,  50},
                { 55,  60,  65,  70,  75,  80,  85,  90,  95, 100},
                {105, 110, 115, 120, 125, 130, 135, 140, 145, 150},
                {155, 160, 165, 170, 175, 180, 185, 190, 195, 200},
                {205, 210, 220, 225, 230, 235, 240, 245, 250, 255}};
          

你仍然有一个由 5 个元素组成的一维数组,你可以像前面的例子一样对它下标,产生以下内容(不是真正的语法,只是你应该如何思考它):

a[0] =   5  10  15  20  25  30  35  40  45  50
a[1] =  55  60  65  70  75  80  85  90  95 100
a[2] = 105 110 115 120 125 130 135 140 145 150
a[3] = 155 160 165 170 175 180 185 190 195 200
a[4] = 205 210 220 225 230 235 240 245 250 255

这里唯一的区别是每个元素不是像上一个示例那样是一个“int”,而是每个元素都是一个数组(由 10 个整数组成)。因此,当您下标时,每个索引(0 到 4)都会返回该行的 10 个整数数组。例如,a[3] 返回包含值 155 到 200 的 10 个整数的数组。元素本身是一个“int[10]”,因此您可以这样对待它。 IOW,你得到的就是这个:

int b[10] = {155, 160, 165, 170, 175, 180, 185, 190, 195, 200};

因此,例如,与 b[7] = 190、a[3][7] = 190 的方式相同,因为 a[3] 有效地返回了 b 的等价物(一个 10整数),然后 [7] 下标抓取该数组索引 7 处的元素,就像 b[7] 一样。此外,同样 b 是指向数组第一个元素的指针(因为所有数组名称都衰减为指向数组第一个元素的指针),在这种情况下为 155(即“b”衰减为一个 int * 指向 155),a[3] 返回(衰减为)相同的东西。为什么?因为它返回了所描述的 b 的等价物,并且就像 b 一样,它衰减为指向其第一个元素的指针。 IOW,就像这是真的:

int *p = b; // "b" decays into a pointer to its first element (an "int")
int val = *p; // Equals 155

这也是真的:

int *p = a[3]; // a[3] returns the equivalent of "b", an int[10], and this decays into a pointer to its first element, just like "b"
int val = *p; // Equals 155

最后,就像 FredOverflow 提到的那样,这也是真的:

int (*p)[10] = a;

语法需要习惯,但它非常有意义。由于每个数组名称都衰减为指向其第一个元素的指针,因此“a”因此衰减为指向其第一个元素的指针。那是什么元素?好吧,“a”的每个元素都是一个由 10 个整数组成的数组,即“int[10]”,因此“a”必须衰减为指向这些“int[10]”元素中的第一个元素的指针。上面的语法就是声明这个指针的方式。它将“p”定义为指向 10 个整数数组的指针。由于 C++ 优先规则,需要(圆)括号。如果你删除它们,你会得到这个:

int *p[10] = a; // Compiler error!

它将“p”声明为一个由 10 个元素组成的数组,其中每个元素都是一个指向 int 的指针。它与 IOW 不同,因此需要括号来更改优先级(以及此声明的含义)。使用前面显示的正确语法,“p”因此将指向第一个元素(“int[10]”数组包含元素 5 到 50),p + 1 将指向第二个元素(“int[10] " 包含元素 55 到 100 的数组)等。奖励点:因此以下会做什么?

(*(p + 3))[5]

它返回 180,因为 (p + 3) 返回指向“a[3]”处的 10 个整数数组的指针,当使用 * 运算符取消引用时,您会在此位置获得实际的“int[10]”数组.然后 [5] 下标在该数组中产生值 180。

毫无疑问,要弄清楚这一点仍然需要大量练习,但我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    然后我建议避免大矩阵的静态堆栈分配,而是选择动态分配(在堆上)...

    【讨论】:

      【解决方案3】:

      为什么 a 等于 *a?

      由于无法打印数组,a 会从 int[10][10] 隐式转换为 int(*)[10]。所以实际上打印出来而不是a 的是指向a 的第一的指针。

      *a 是数组的第一行,然后将其转换为指向第一个元素的指针。

      由于数组与其第一个元素具有相同的地址,因此两次获得相同的值。

      【讨论】:

        【解决方案4】:

        为什么a 等于*a

        当在需要指针的上下文中使用时,数组将被转换为指向其第一个元素的指针。 a 是一个数组数组;所以它会衰减到指向第一个数组的指针。 *a 是第一个数组,并将衰减为指向该数组中第一个整数的指针。这两者都存在于同一位置,因此两个指针将具有相等的值。

        为什么 *a 不等于 *ptr?

        因为从数组数组到指针到指针的转换无效。您已经使用强制转换强制转换 - 危险的 C 风格转换,在这种情况下就像 reinterpret_cast - 所以 *ptr 将读取数组的前几个字节并将其解释为指针(可能 - 行为这里是未定义的,所以原则上任何事情都可能发生)。 ptr指向的内存中没有指针,所以*ptr肯定不会给你一个有效的指针。

        【讨论】:

          【解决方案5】:

          二维 C 数组不是指向指针的指针。 IT 实际上是一个指针,其中包含行 * 列元素。

          int main(){
              int a[10][10];
              int *ptr =(int *)a;
              cout<<a<<endl<<ptr<<endl;
              cout<<*a<<endl<<*ptr<<endl;
              return 0;
          }
          

          以上内容将为您提供您所追求的。

          虽然当你取消引用 a 或 ptr 时你会发现你得到一个“未定义的值”

          如果你将 a[4][4] 设置为 5

          然后你会找到存储在的值

          ptr[(row * 10) + column) 将返回 row = 4 和 column = 4 的值。

          【讨论】:

          • 数组不是指针。有一个从数组到指针的转换,但这并不能使它们相同。
          • int *ptr =(int *)a; 也是非法的。你可以写int *ptr = a[0];int (*ptr)[10] = a;
          • @Goz 为什么“a”和“*a”的值是一样的? "*a" 应该给我 a[0][0].. 的内容
          猜你喜欢
          • 1970-01-01
          • 2015-10-28
          • 2017-04-26
          • 1970-01-01
          • 2017-06-11
          • 1970-01-01
          • 2013-01-26
          • 2016-05-08
          相关资源
          最近更新 更多