C++中指向数组的指针 vs 指向数组元素的指针

110 阅读2分钟

基本分析

现有如下的定义:

 int a[]{1, 2, 3, 4, 5};
 // 定义一个指向数组的指针
 int (*p1)[5] = &a;
 // 定义一个指向数组元素的指针
 int *p2 = a;

我们尝试打印他们的输出:

 cout << p1 << endl;
 cout << p2 << endl;
 cout << a << endl;

得到结果:

 0xa3f0fffa00
 0xa3f0fffa00
 0xa3f0fffa00

可以看到,三者都指向同一个地址,也就是数组a的首个元素的地址。我们再尝试解引用p1p2

 cout << *p1 << endl;
 cout << *p2 << endl;
 cout << a << endl;

得到结果:

 0xa2c3ff7f0
 1
 0xa2c3ff7f0

解引用指针p2得到a中的首个元素,而解引用指针p1 我们得到的依然是一个数组的地址,似乎是否解引用对指针p1并无影响。

遍历分析

我们尝试使用range for 语句来对三者进行分析,先尝试对p1进行遍历,因为我们在输出中发现p1指向的地址与a相同:

 for (auto it : p1) {
     cout << it;
 }

我们发现:

 error: 'end' was not declared in this scope; did you mean 'std::end'?

p1进行解引用:

 for (auto it : *p1) {
     cout << it;
 }

得到了正常输出的结果:

 12345

再尝试对p2进行遍历:

 for (auto it : p2) {
     cout << it;
 }

得到错误:

 error: 'end' was not declared in this scope; did you mean 'std::end'?

那么我们就得到了结论:

p1p2a虽然指向了同一个地址,但是type不相同,我们能做的操作也不同。正如 《C++ Primer》一书中说到,type决定了你可以如何操作这些数据。虽然我们使用p2也能对数组进行遍历,但是p1是抽象层面上指向数组的指针,我们对其进行解引用,理应能做能够对数组做的一些操作,如上文中的range-for遍历。