#include<bits/stdc++.h>
using namespace std;
int main()
{
int a[101][101];
a[2][0]=10;
cout<<a+2<<endl;
cout<<*(a+2)<<endl;
cout<<*(*(a+2));
return 0;
}
为什么
a+2
和*(a+2)
的值相同?
提前致谢!
a
是一个二维数组,即数组的数组。但当在适当的上下文中使用时,它会“衰减”为指向数组的指针。所以:
在 a+2
a
衰减为指向大小为 101 的 int 数组的指针。当您将 is 传递给 ostream 时,您将获得该数组的第一个元素的地址,即 &(a[2][0])
*(a+2)
根据定义是
a[2]
:它是一个从a[2][0]
开始、大小为101的数组。它衰减为一个指向 int 的指针,当你将它传递给 ostream 时,你会得到它的第一个元素的地址,它仍然是 &(a[2][0])
**(a+2)
根据定义
a[2][0]
。当你将它传递给 ostream 时,你会得到它的 int 值,这里是 10。
a + 2
和
a[2]
都是指向同一地址的指针(static_cast<void *>(a+2)
与static_cast<void *>(a[2])
相同),但它们是指向不同类型的指针:第一个指向大小为101的int数组,后者指向int.让我们考虑一个更实用的多维数组示例:
int a[3][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
可以执行命令
x/10w a
在GDB中查看内存:
0x7fffffffe750: 1 2 3 4
0x7fffffffe760: 5 6 7 8
0x7fffffffe770: 9 0
每个元素都存储为int
类型(32 位/4 字节)。
所以矩阵的第一个元素已存储在:
1) a[0][0] -> 0x7fffffffe750
2) a[0][1] -> 0x7fffffffe754
3) a[0][2] -> 0x7fffffffe758
4) a[1][0] -> 0x7fffffffe75c
5) a[1][1] -> 0x7fffffffe760
6) a[1][2] -> 0x7fffffffe764
7) a[2][0] -> 0x7fffffffe768
...
命令:
std::cout << a + 2 << '\n'
它将打印地址0x7fffffffe768
因为 指针算术: a 的类型是 int** 所以它是一个指向指针的指针。 a+2 是 a[0](第一行)+ 2。结果是一个指针 到第三排。 *(a+2) 遵循第三行,即 {7,8,9}
第三行是一个int数组,它是一个指向int的指针。
然后是操作员
<< will print the value of that pointer.
char v[2][3] = {{1,3,5},{5,10,2}};
Content: | 1 | 3 | 5 | 5 | 10 | 2
Address: v v+1 v+2 v+3 v+4 v+5
要访问 v[x][y],编译器将其重写为:
*(v + y * M + x)
(其中 M 是指定的第二个维度)
例如,要访问 v[1][1],编译器将其重写为
*(v + 1*3 + 1)
=>
*(v + 4)
请注意,这与指向指针 (char**) 的指针不同。 指向指针的指针不是数组:它包含指向内存单元的地址,该内存单元包含另一个地址。
要使用指向指针的指针访问二维数组的成员,请执行以下操作:
char **p;
/* Initialize it */
char c = p[3][5];
前往
p
内容指定的地址;char p[10][10];
char c = p[3][5];
获取
p
的地址,并将第一个偏移量 (3) 乘以行的尺寸 (10)。然后数组的名称会隐式转换为指向其第一个元素的指针,但极少数例外(例如在
sizeof
运算符中使用数组名称)。
因此,例如在表达式
( a + 2 )
a
中,转换类型
T *
的值为 &a[0]
。相对于您的数组示例
int a[101][101];
表达中
a + 2
a 转换为
int ( * )[101]
类型的右值并指向数组的第一“行”。
a + 2
指向数组的第三“行”。行的类型是
int[101]
表达式
*(a+2)
给出了类型为 int[101]
的第三行,它是一个数组。这个数组在表达式中使用时会依次转换为指向其第一个类型为
int *
的元素的指针。 与第三行占用的内存区域起始地址相同
只有表达式
( a + 2 )
具有类型
int ( * )[101]
,而表达式
*( a + 2 )
具有类型 int *
。但两者产生相同的值 - 数组第三行占用的内存区域的起始地址a
。数组的第一个元素与数组本身位于同一位置 - 数组中没有“空白空间”。
cout << a + 2
中,
a
被隐式转换为指向其第一个元素
&a[0]
的指针,而 a + 2
是 a
的第三个元素 &a[2]
的位置。 在
cout << *(a + 2)
中,数组 *(a + 2)
- 即
a[2]
- 被转换为指向其第一个元素 &a[2][0]
的指针。由于
a
的第三个元素的位置和 a
的第三个元素的第一个元素的位置相同,因此输出相同。