澄清数组和指针的关系
Clarification on the relation of arrays and pointers
我想进一步了解并可能澄清一些让我对 C++ 中的数组和指针感到困惑的事情。让我感到困惑的一个主要问题是,当您引用数组的名称时,它可能指的是数组,或者作为指向第一个元素的指针,以及其他一些东西。为了更好地展示我理解上的问题是从哪里来的,我将展示几行代码,以及我从每一行代码中得出的结论。
假设我有
int vals[] = {1,50,3,28,32,500};
int* valptr = vals;
因为 vals 是指向数组第一个值的指针,这意味着 valptr 应该等于整个 vals,因为我只是将指针设置为等于指针,例如 1=1。
cout<<vals<<endl;
cout<<&vals<<endl;
cout<<*(&vals)<<endl;
cout<<valptr<<endl;
上面的代码都打印出相同的值,这让我得出了两点结论,一个是 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
上面的代码进一步深化了我的心态,即 valptr 和 vals 是相同的,因为每当我对 vals 做某事,并对 valptr 做同样的事情时,它们都会产生相同的结果
cout<<*(&valptr +1)-valptr<<endl;
cout<<endl;
cout<< *(&vals + 1) -vals<<endl;
现在我们已经确定了我所知道的,或者我可能有的误解,现在我们继续讨论我遇到的两个主要问题,我们现在将讨论这些问题。
我的第一个困惑是 cout<< *(&vals + 1) -vals<<endl;
我知道这会输出数组的大小,以及它如何工作的一般概念,但我在几个部分感到困惑。
如前所示,if
cout<<vals<<endl;
cout<<&vals<<endl;
cout<<*(&vals)<<endl;
都打印出相同的值,为什么我需要 * 和 & 在 cout<< *(&vals + 1) -vals<<endl;
我知道如果我这样做 vals+1
它只是指下一个元素的地址数组,意思是*(vals+1)
returns50。
这让我想到了我的第一个问题:为什么 *(&vals+1)
中的 & 引用数组中的下一个地址?为什么它与 (vals+1)
的输出不同,而 *(&vals)
和 (vals)
具有相同的输出?
现在回答我的第二个问题。我们知道cout<< *(&vals + 1) -vals<<endl;
是一个有效的语句,成功打印了数组的大小。但是,正如我之前所说,在所有其他情况下,valptr
可以互换地替换为 vals
。但是,在写 cout<<*(&valptr +1)-valptr<<endl;
的实例中,我返回了 0,而不是预期值 6。以前被证明可以互换的东西,在这种情况下怎么可能不再可以互换?
我感谢任何阅读本文的人能给我的帮助
数组和指针是 C++ 中的两种不同类型,它们之间有足够的相似性,如果不正确理解它们就会造成混淆。指针是初学者最难掌握的概念之一这一事实也无济于事。
所以我认为需要快速速成课程。
速成班
数组,简单
int a[3] = {2, 3, 4};
这将创建一个名为 a
的数组,其中包含 3 个元素。
数组定义了数组下标运算符:
a[i]
计算数组的第 i
个元素。
指针,简单
int val = 24;
int* p = &val;
p
是指向对象地址的指针val
.
指针定义了 间接(取消引用) 运算符:
*p
求值为p
指向的对象的值。
指针,类似于数组
指针为您提供对象在内存中的地址。它可以是上面示例中的“独立对象”,也可以是属于数组一部分的对象。指针类型和指针值都不能告诉您它是哪一个。只是程序员。这就是为什么
指针还定义了数组下标运算符:
p[i]
计算 p
指向的对象“右侧”的第 i
个元素。这假定 p
的对象指针是数组的一部分(在 p[0]
中除外,它不需要是数组的一部分)。
请注意 p[0]
等同于(完全相同)*p
。
数组,类似于指针
在大多数情况下,数组名称会衰减为指向数组中第一个元素的指针。这就是为什么很多初学者认为数组和指针是一回事的原因。事实上他们不是。它们是不同的类型。
回到你的问题
Because vals is a pointer to the first value of the array
不,不是。
... then that means that valptr, should equal vals as a whole, since I'm just setting a pointer equal to a pointer, like 1=1.
因为前提是假的,其余句子也是假的。
valptr and vals are equal
不,他们不是。
can be treated in the same way
大多数时候是的,因为数组到指针衰减。然而,情况并非总是如此。例如。作为 sizeof
的表达式和 &
运算符的操作数(地址)。
Why does the & in *(&vals+1)
refer to the next address out the array?
&vals
这是 vals
不衰减为指针的少数情况之一。 &vals
是数组的地址,类型为 int (*)[6]
(指向 6 个整数的数组的指针)。这就是为什么 &vals + 1
是数组 vals
.
右侧的假设另一个数组的地址
How can something that was proven to be interchangeable before, no longer be interchangeable in this instance?
就是这样。在大多数情况下,数组的名称会衰减为指向数组第一个元素的指针。除了我提到的几种情况。
更多速成课程
指向数组的指针与指向数组第一个元素的指针不同。获取数组的地址是数组名称不会衰减到指向其第一个元素的指针的少数实例之一。
所以&a
是指向数组的指针,不是指向数组首元素的指针。数组和数组的第一个元素都从相同的地址开始,因此两者的值(&a
和 &a[0]
)相同,但它们的类型不同,这在您应用对它们取消引用或数组下标运算符:
Expression
Expression type
Dereference / array subscript
expresison
Dereference / array subscript
type
a
int[3]
*a
/ a[i]
int
&a
int (*) [3]
(pointer to array)
*&a
/ &a[i]
int[3]
&a[0]
int *
*&a[0]
/ (&a[0])[i]
int
我想进一步了解并可能澄清一些让我对 C++ 中的数组和指针感到困惑的事情。让我感到困惑的一个主要问题是,当您引用数组的名称时,它可能指的是数组,或者作为指向第一个元素的指针,以及其他一些东西。为了更好地展示我理解上的问题是从哪里来的,我将展示几行代码,以及我从每一行代码中得出的结论。
假设我有
int vals[] = {1,50,3,28,32,500};
int* valptr = vals;
因为 vals 是指向数组第一个值的指针,这意味着 valptr 应该等于整个 vals,因为我只是将指针设置为等于指针,例如 1=1。
cout<<vals<<endl;
cout<<&vals<<endl;
cout<<*(&vals)<<endl;
cout<<valptr<<endl;
上面的代码都打印出相同的值,这让我得出了两点结论,一个是 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
上面的代码进一步深化了我的心态,即 valptr 和 vals 是相同的,因为每当我对 vals 做某事,并对 valptr 做同样的事情时,它们都会产生相同的结果
cout<<*(&valptr +1)-valptr<<endl;
cout<<endl;
cout<< *(&vals + 1) -vals<<endl;
现在我们已经确定了我所知道的,或者我可能有的误解,现在我们继续讨论我遇到的两个主要问题,我们现在将讨论这些问题。
我的第一个困惑是 cout<< *(&vals + 1) -vals<<endl;
我知道这会输出数组的大小,以及它如何工作的一般概念,但我在几个部分感到困惑。
如前所示,if
cout<<vals<<endl;
cout<<&vals<<endl;
cout<<*(&vals)<<endl;
都打印出相同的值,为什么我需要 * 和 & 在 cout<< *(&vals + 1) -vals<<endl;
我知道如果我这样做 vals+1
它只是指下一个元素的地址数组,意思是*(vals+1)
returns50。
这让我想到了我的第一个问题:为什么 *(&vals+1)
中的 & 引用数组中的下一个地址?为什么它与 (vals+1)
的输出不同,而 *(&vals)
和 (vals)
具有相同的输出?
现在回答我的第二个问题。我们知道cout<< *(&vals + 1) -vals<<endl;
是一个有效的语句,成功打印了数组的大小。但是,正如我之前所说,在所有其他情况下,valptr
可以互换地替换为 vals
。但是,在写 cout<<*(&valptr +1)-valptr<<endl;
的实例中,我返回了 0,而不是预期值 6。以前被证明可以互换的东西,在这种情况下怎么可能不再可以互换?
我感谢任何阅读本文的人能给我的帮助
数组和指针是 C++ 中的两种不同类型,它们之间有足够的相似性,如果不正确理解它们就会造成混淆。指针是初学者最难掌握的概念之一这一事实也无济于事。
所以我认为需要快速速成课程。
速成班
数组,简单
int a[3] = {2, 3, 4};
这将创建一个名为 a
的数组,其中包含 3 个元素。
数组定义了数组下标运算符:
a[i]
计算数组的第 i
个元素。
指针,简单
int val = 24;
int* p = &val;
p
是指向对象地址的指针val
.
指针定义了 间接(取消引用) 运算符:
*p
求值为p
指向的对象的值。
指针,类似于数组
指针为您提供对象在内存中的地址。它可以是上面示例中的“独立对象”,也可以是属于数组一部分的对象。指针类型和指针值都不能告诉您它是哪一个。只是程序员。这就是为什么
指针还定义了数组下标运算符:
p[i]
计算 p
指向的对象“右侧”的第 i
个元素。这假定 p
的对象指针是数组的一部分(在 p[0]
中除外,它不需要是数组的一部分)。
请注意 p[0]
等同于(完全相同)*p
。
数组,类似于指针
在大多数情况下,数组名称会衰减为指向数组中第一个元素的指针。这就是为什么很多初学者认为数组和指针是一回事的原因。事实上他们不是。它们是不同的类型。
回到你的问题
Because vals is a pointer to the first value of the array
不,不是。
... then that means that valptr, should equal vals as a whole, since I'm just setting a pointer equal to a pointer, like 1=1.
因为前提是假的,其余句子也是假的。
valptr and vals are equal
不,他们不是。
can be treated in the same way
大多数时候是的,因为数组到指针衰减。然而,情况并非总是如此。例如。作为 sizeof
的表达式和 &
运算符的操作数(地址)。
Why does the & in
*(&vals+1)
refer to the next address out the array?
&vals
这是 vals
不衰减为指针的少数情况之一。 &vals
是数组的地址,类型为 int (*)[6]
(指向 6 个整数的数组的指针)。这就是为什么 &vals + 1
是数组 vals
.
How can something that was proven to be interchangeable before, no longer be interchangeable in this instance?
就是这样。在大多数情况下,数组的名称会衰减为指向数组第一个元素的指针。除了我提到的几种情况。
更多速成课程
指向数组的指针与指向数组第一个元素的指针不同。获取数组的地址是数组名称不会衰减到指向其第一个元素的指针的少数实例之一。
所以&a
是指向数组的指针,不是指向数组首元素的指针。数组和数组的第一个元素都从相同的地址开始,因此两者的值(&a
和 &a[0]
)相同,但它们的类型不同,这在您应用对它们取消引用或数组下标运算符:
Expression | Expression type | Dereference / array subscript expresison |
Dereference / array subscript type |
---|---|---|---|
a |
int[3] |
*a / a[i] |
int |
&a |
int (*) [3] (pointer to array) |
*&a / &a[i] |
int[3] |
&a[0] |
int * |
*&a[0] / (&a[0])[i] |
int |