澄清数组和指针的关系

MmM*_*sSs 1 c++ arrays pointers

我想要进一步了解,并可能澄清一些让我对 C++ 中的数组和指针感到困惑的事情。让我困惑的主要事情之一是,当您引用数组的名称时,它可能是指该数组,或者是指向第一个元素的指针,以及其他一些东西。为了更好地显示我的理解困难来自哪里,我将显示几行代码,以及我从每行代码中得出的结论。

假设我有

  int vals[] = {1,50,3,28,32,500};
  int* valptr = vals;
Run Code Online (Sandbox Code Playgroud)

因为 vals 是指向数组第一个值的指针,所以这意味着 valptr 作为一个整体应该等于 vals,因为我只是将一个指针设置为等于一个指针,例如 1=1。

cout<<vals<<endl;
cout<<&vals<<endl;
cout<<*(&vals)<<endl;
cout<<valptr<<endl;
Run Code Online (Sandbox Code Playgroud)

上面的代码打印出相同的值,这让我得出两件事的结论,一是 valptr 和 vals 相等,并且可以以相同的方式处理,另一个事实是,由于某种原因,将 & 和 * 添加到vals 似乎没有指代任何不同的东西,这意味着以这种方式使用它们是没有用的,因为它们都指的是相同的值。

cout<<valptr[1]<<endl;//outputs 50
cout<<vals[1]<<endl;//outputs 50
cout<<*vals<<endl;//outputs 1
cout<<*valptr<<endl;//outputs 1
Run Code Online (Sandbox Code Playgroud)

上面的代码进一步加深了我的心态,valptr 和 vals 是相同的,每当我对 vals 执行某些操作,并对 valptr 执行相同的操作时,它们都会产生相同的结果

cout<<*(&valptr +1)-valptr<<endl;


cout<<endl;

cout<< *(&vals + 1) -vals<<endl;
Run Code Online (Sandbox Code Playgroud)

现在我们已经确定了我所知道的,或者我可能有的误解,现在我们继续讨论我遇到的两个主要问题,我们现在将讨论这些问题。

我的第一个困惑是cout<< *(&vals + 1) -vals<<endl;我知道这输出了数组的大小,以及它如何工作的一般概念,但我对几个部分感到困惑。如前所述,如果

cout<<vals<<endl;
cout<<&vals<<endl;
cout<<*(&vals)<<endl;
Run Code Online (Sandbox Code Playgroud)

全部打印出相同的值,为什么我需要 * 和 & ,cout<< *(&vals + 1) -vals<<endl;我知道如果我这样做,vals+1它只是指数组上下一个元素的地址,这意味着*(vals+1)返回 50。这引出了我的第一个问题:为什么 & in*(&vals+1)引用数组中的下一个地址?为什么它的输出与和具有相同输出的(vals+1)方式不同?*(&vals)(vals)

现在我的第二个问题。我们知道这cout<< *(&vals + 1) -vals<<endl;是一个有效的语句,成功打印了数组的大小。然而,正如我之前所说,在所有其他情况下,都valptr可以互换替换vals。然而,在写入的实例中,cout<<*(&valptr +1)-valptr<<endl;我返回了 0,而不是预期的 6。以前被证明可以互换的东西在这种情况下怎么可能不再可以互换呢?

我感谢阅读本文的任何人可以给我的任何帮助

bol*_*lov 5

数组和指针是 C++ 中的两种不同类型,它们之间有足够的相似之处,如果不能正确理解它们,就会造成混乱。指针是初学者最难掌握的概念之一,这一事实也无济于事。

所以我觉得需要快速速成课程。

速成课程

数组,简单

int a[3] = {2, 3, 4};
Run Code Online (Sandbox Code Playgroud)

这将创建一个名为 的数组a,其中包含 3 个元素。

数组定义了数组下标运算符:

a[i]
Run Code Online (Sandbox Code Playgroud)

计算结果为i数组的第 ' 个元素。

指针,简单

int val = 24;
int* p = &val;
Run Code Online (Sandbox Code Playgroud)

p是一个指向对象地址的指针val

指针定义了间接(取消引用)运算符:

*p
Run Code Online (Sandbox Code Playgroud)

计算结果为 指向的对象的值p

指针,作用类似于数组

指针为您提供内存中对象的地址。它可以是像上面的示例中那样的“独立对象”,也可以是属于数组一部分的对象。指针类型和指针值都无法告诉您它是哪一种。只是程序员。这就是为什么

指针还定义了数组下标运算符:

p[i]

计算出i指向的对象“右侧”的第 th 个元素p。这假设对象指针 byp是数组的一部分(除非p[0]它不需要是数组的一部分)。

请注意p[0]相当于(完全相同)*p

数组,作用类似于指针

在大多数情况下,数组名称会衰减为指向数组中第一个元素的指针。这就是为什么许多初学者认为数组和指针是同一个东西。事实上他们不是。它们是不同的类型。

回到你的问题

因为 vals 是指向数组第一个值的指针

不,这不对。

...那么这意味着 valptr 作为一个整体应该等于 vals,因为我只是将一个指针设置为等于一个指针,例如 1=1。

因为前提是假的,所以句子的其余部分也是假的。

valptr 和 vals 相等

不,他们不是。

可以用同样的方法治疗

大多数时候是的,因为数组到指针的衰减。然而情况并非总是如此。例如,作为(地址)运算符的表达式sizeof和操作数。&

为什么 & in*(&vals+1)引用数组中的下一个地址?

&valsvals这是不衰减为指针的少数情况之一。&vals是数组的地址,类型为int (*)[6](指向 6 个整数的数组的指针)。这就是为什么&vals + 1假设的另一个数组的地址位于该数组的右侧vals

以前被证明可以互换的东西,在这种情况下怎么就不再可以互换了呢?

简单地说,这就是语言。在大多数情况下,数组的名称会衰减为指向数组第一个元素的指针。除了我提到的几种情况。

更多速成课程

指向数组的指针与指向数组第一个元素的指针不同。获取数组的地址是数组名称不会衰减为指向其第一个元素的指针的少数实例之一。

&a指向数组的指针也是如此,而不是指向数组第一个元素的指针。数组和数组的第一个元素都从相同的地址开始,因此两个 (&a&a[0]) 的值相同,但它们的类型不同,这在您对它们应用取消引用或数组下标运算符时很重要:

表达 表达类型 解引用/数组下标
表达式
解引用/数组下标
类型
a int[3] *a/a[i] int
&a int (*) [3]
(指向数组的指针)
*&a/&a[i] int[3]
&a[0] int * *&a[0]/(&a[0])[i] int