我目前在我的大学编程2。我们正在进行一项测试,只是想要对我在指针上放置的一些内容进行一些确认。请考虑以下代码:
//CASE 1
int Awesome = 10; //Line 1
int *P = &Awesome; //Line 2
cout << Awesome << endl; //Line 3
cout << *P << endl; //Line 4
//CASE 2
int X[3]={0,0,5}; //Line 1
int *A = X; //Line 2
cout << X[2] << endl; //Line 3
cout << A[2] << endl; //Line 4
这里是我的问题所在,但我认为我有点&#34;跌跌撞撞&#34;我的问题的答案,但我想确保它的正确。
在第一行2中,我声明指针P
并使用引用运算符给它Awesome
的地址。在第二行2中,我声明指针A
并为其指定X
的地址。我永远不明白为什么在给指针提供数组地址的情况下我们没有使用&
运算符。在考虑之后,我记得听说数组名称只是一个包含数组第一个下标地址的常量指针。如果这是正确的,那么为什么我们不需要使用&
来获取数组的地址是有道理的,因为数组名称本身已经包含了地址。这是对的吗?
我的第二个问题。在第一行4中,我cout
- 使用取消引用运算符指向P
指针的内容,但在第二行第4行中,我不知道需要使用*
运算符来获取值。在我的脑海中,我不确定为什么它有所不同,但我认为上面段落中的概念使其更加清晰。数组名称本身和指针基本相同(除了数组名称是我认为的常量指针)。数组名称是一个常量指针,用于保存地址,指针正在获取此地址。因此,我们使用新指针以相同的方式保存新地址。它与第一个实例完全不同。由于数组名称和指针基本相同,因此我们不需要使用特殊的*
运算符,只需像使用数组表示法的普通数组一样使用它。这是对的吗?
我一直在努力理解为什么上述两个概念不同,为什么在一个实例(int *P = &Address
)中我们需要使用&
运算符来提供地址以及为什么在另一个实例中(int *A=X
)我们没有。我一直在努力解决为什么我们在一个实例(*
)中使用cout << *P;
而在另一个实例中使用cout << A[2];
(sudo chmod 755 /path/to/css or javascript file/
)。这些差异使我感到很困惑,但如果我的逻辑与我的逻辑接近正确,那么现在就完全有道理了。如果完全错误,任何人都可以确认或更正吗?
答案 0 :(得分:3)
C / C ++中的数组和指针之间存在一个重要的区别。
假设:
int a[10];
int *p = a;
sizeof(a)
将返回10*sizeof(int)
(可能== 40或80)。 sizeof(p)
将返回sizeof(int*)
(可能== 4或8)。
数组解除扩展也适用于C / C ++中的指针。所以你可以写p[1]
或*(p + 1)
。
如果有帮助你也可以写:
int *p = &a[0];
这对于编写适用于std::vector
,std::array
,普通C / C ++数组或任何其他容器的模板代码特别有用,该容器将其元素存储在连续的内存块中并提供数组接口。
编辑:我还要补充一点,由于别名编译器应该能够比指针解除扩展更好地优化数组访问。
答案 1 :(得分:2)
不正式正确,数组和指针的类型相同。
这是使用重载函数的证明。第一个重载通过引用获取数组,第二个重载通过引用获取指针。它表明int[8]
和int*
是不同的类型。
#include <iostream>
void f(int (&x) [8]) {
std::cout << "array type\n";
}
void f(int*& y) {
std::cout << "pointer type\n";
}
int main()
{
int x[8];
int* y;
f(x);
f(y);
}
真正的是,数组很容易转换为指向第一个元素的指针。当初学者尝试按值将数组传递给函数时,通常会发生这种情况。必须有一个问题,为什么这在Stackoverflow每2或3天不起作用。这种转换意味着,例如,函数void f(int x[8])
和void f(int* x)
将彼此相同(并且编译器会抱怨重新定义)。最重要的是,这当然意味着丢失了作为数组类型一部分的大小信息([8]
)。
转换非正式地称为“衰变”,它也会在分配或初始化时发生,如下所示:
int X[3]={0,0,5}; //Line 1 int *A = X; //Line 2
这并不意味着int[3]
和int*
完全相同,就像int
和double
之所以不相同,只是因为您可以写my_double = my_int;
。< / p>
如果那是正确的,那么为什么我们不需要这样才有意义 使用&amp;获取数组的地址,因为数组名称 本身已包含地址。这是对的吗?
没有。您做需要使用&
来获取数组的地址。您不需要它来获取其第一个元素中包含的值。
在你的例子中:
int X[3]={0,0,5}; //Line 1 int *A = X; //Line 2
std::cout << &X;
将为您提供本地数组对象的地址。
由于数组名称和指针基本相同,我们不会 需要使用特殊的*运算符,只需像普通数组一样使用它 使用数组表示法。这是对的吗?
嗯,这取决于你对狡猾的词“基本上”的真正含义。
毕竟,下标运算符只是指针算术 [*] 的语法糖。根据定义,t[n]
等于*(t + n)
(具有讽刺意味的是,与*(n + t)
相同,因此与n[t]
相同。)
int X[3]={0,0,5}; //Line 1 int *A = X; //Line 2 cout << X[2] << endl; //Line 3 cout << A[2] << endl; //Line 4
在第3行中,您执行*(X + 2)
。没关系。 X
“衰减”到指向其第一个元素的指针,然后将2添加到该指针。添加指针的结果将被取消引用。
在第4行中,您执行*(A + 2)
。那也没关系。唯一的区别是没有“腐烂”发生; A
已经是指针类型。
顺便说一句......在你的问题和评论中,你不断提到“数组名称本身只是持有一个地址”。这意味着比你认为的要少。毕竟,它只是说明一个非常简单的事实,即变量的名称表示一个存在于内存中的对象,因此必须有一个地址。你可以说一个简单的int
变量。例如,在int x = 123;
中,可以说“int名称本身只是持有一个地址”。这有点真实,但我不认为这对于试图理解数组和指针的人来说是一个有用的难题。
[*]当然,证明语法糖对编写可维护代码非常重要! :)功能
答案 2 :(得分:1)
您对阵列的见解是正确的。数组变量可以视为指针。当你宣布
时int x[8];
int* y;
然后,x
和y
都与int*
类型兼容。主要区别在于x
指向堆栈上的一系列地址,具有足够的容量来存储8个整数,而y
未初始化。
此外,*x
和x[0]
是两种相同的解除引用方式。
*x == x[0]
*(x+n) == x[n]