寻找关于指针使用差异的一些确认

时间:2016-02-20 08:02:06

标签: c++ arrays pointers reference dereference

我目前在我的大学编程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/ )。这些差异使我感到很困惑,但如果我的逻辑与我的逻辑接近正确,那么现在就完全有道理了。如果完全错误,任何人都可以确认或更正吗?

3 个答案:

答案 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::vectorstd::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*完全相同,就像intdouble之所以不相同,只是因为您可以写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;

然后,xy都与int*类型兼容。主要区别在于x指向堆栈上的一系列地址,具有足够的容量来存储8个整数,而y未初始化。

此外,*xx[0]是两种相同的解除引用方式。

*x == x[0]
*(x+n) == x[n]