C ++返回指针/引用

我对解引用操作符,操作符的地址和指针有一个相当好的理解。

然而,当我看到像这样的东西时,我感到困惑:

int* returnA() { int *j = &a; return j; } int* returnB() { return &b; } int& returnC() { return c; } int& returnC2() { int *d = &c; return *d; } 
  1. returnA()我要求返回一个指针; 只是为了澄清这个作品,因为j是一个指针?
  2. returnB()我要求返回一个指针; 因为指针指向一个地址, returnB()的原因是因为我返回&b
  3. returnC()我要求返回int的地址。 当我返回c&运算符自动“附加” c
  4. returnC2()我再次要求返回int的地址。 *d是否工作,因为指针指向一个地址?

假设a,b,c被初始化为整数。

有人能validation我的四个问题是否正确吗?

在returnA()我要求返回一个指针; 只是为了澄清这个作品,因为j是一个指针?

是的, int *j = &a初始化j指向a 。 然后你返回j的值,就是a的地址。

在returnB()我要求返回一个指针; 因为指针指向一个地址,returnB()的原因是因为我返回&b?

是。 这里同样的事情发生在上面,只需一步。 &b给出&b的地址。

在returnC()我要求返回int的地址。 当我返回c是&运算符自动附加?

不,它是对返回的int的引用。 引用的地址与指针不同 – 它只是一个variables的替代名称。 因此,您不需要应用&运算符来获取variables的引用。

在returnC2()我再次要求返回int的地址。 * d是否工作,因为指针指向一个地址?

同样,它是对返回的int的引用。 *d指的是由c指向的原始variablesc (不pipe可能是什么)。 这可以隐含地变成一个引用,就像在returnC

指针通常不指向地址(虽然它们可以 – 例如int**是指向int**的指针)。 指针一些东西的地址。 当你将这个指针声明为something* ,指针指向的something就是这个东西。 所以在我上面的例子中, int**声明了一个指向int*的指针,这恰好是一个指针本身。

虽然彼得回答你的问题,但是显而易见的一点是符号*& 。 关于如何解决这些问题的难点在于它们都有两个不同的含义,它们与间接性有关(甚至不包括乘法的第三种含义,以及对于按位的含义)。

  • * ,当用作types的一部分时,表示该types是一个指针: int是一个types,所以int*是指向inttypes的指针, int**是指向inttypes的指针。

  • 当用作types的一部分时,表示该types是引用。 int是一个types,所以int&是一个引用到int(没有引用参考的东西)。 引用和指针用于类似的东西,但是它们是非常不同的,不可互换的。 一个引用最好被认为是一个现有variables的别名或替代名称。 如果x是一个int ,那么你可以简单地指定int& y = xint& y = x创build一个新的名字y 。 后缀, xy可以互换使用来表示相同的整数。 这两个主要的含义是引用不能为NULL(因为必须有一个原始的variables来引用),并且你不需要使用任何特殊的操作符来获得原始值(因为它只是一个替代名称,不是指针)。 引用也不能被重新分配。

  • *作为一元运算符使用时,执行称为解除引用的操作(与引用types无关!)。 这个操作只对指针有意义。 当你引用一个指针时,你会回到它指向的地方。 所以,如果p是一个指向int的指针, *p是指向的int

  • 当作为一元运算符使用时,执行一个称为address-of的操作。 这是不言自明的; 如果x是一个variables,那么&x&x的地址。 一个variables的地址可以分配给一个指向该variablestypes的指针。 所以,如果x是一个int ,那么&x可以被分配给一个types为int*的指针,并且该指针将指向x 。 例如,如果您分配int* p = &x ,则可以使用*p来检索x的值。

所以请记住,types后缀&是用于引用,并且与一元操作符&无关,这与获取用于指针的地址有关。 这两个用途是完全无关的。 *作为types后缀声明一个指针,而*作为一元运算符对指针执行一个操作。

泰勒,这是非常有帮助的解释,我做了一些实验,使用Visual Studiodebugging器,进一步澄清这种差异: –

 int sample = 90; int& alias = sample; int* pointerToSample = &sample; Name Address Type &alias 0x0112fc1c {90} int * &sample 0x0112fc1c {90} int * pointerToSample 0x0112fc1c {90} int * *pointerToSample 90 int alias 90 int & &pointerToSample 0x0112fc04 {0x0112fc1c {90}} int * * 

内存布局

 PointerToSample Sample/alias _______________......____________________ 0x0112fc1c | | 90 | ___________|___.....__|________|_______... [0x0112fc04] ... [0x0112fc1c 

在returnC()和returnC2()中,你不是要求返回地址。

这两个函数都返回对象的引用。
一个引用不是任何东西的地址,它是某种东西的替代名称(这可能意味着编译器可能(或者可能不依赖于情况)使用地址来表示对象(或者也可能知道将其保存在寄存器中)) 。

你知道一个参考点指向一个特定的对象。
虽然引用本身不是一个对象只是一个替代名称。

所有的例子都会产生未定义的运行时行为。 您正在返回指针或对执行离开函数后消失的项目的引用。

让我澄清一下:

 int * returnA() { static int a; // The static keyword keeps the variable from disappearing. int * j = 0; // Declare a pointer to an int and initialize to location 0. j = &a; // j now points to a. return j; // return the location of the static variable (evil). } 

在你的函数中,variablesj被分配指向a临时的位置。 当你的函数退出时,variablesa消失,但是它的前一个位置是通过j返回的。 由于j指向的位置不再存在,因此访问*j会发生未定义的行为。

函数内的variables不应该通过引用或其他代码的指针来修改。 它可能发生,虽然它产生未定义的行为。

迂腐,返回的指针应该被声明为指向常量数据。 返回的引用应该是const:

 const char * Hello() { static const char text[] = "Hello"; return text; } 

上面的函数返回一个指向常量数据的指针。 其他代码可以访问(读取)静态数据,但不能修改。

 const unsigned int& Counter() { static unsigned int value = 0; value = value + 1; return value; } 

在上面的函数中,第一个条目的value被初始化为零。 该函数的所有下一个执行都会使value增加1。 该函数返回一个常量值的引用。 这意味着其他函数可以使用该值(从远处),就像它是一个variables(而不必取消引用指针)。

在我看来,一个指针用于一个可选的参数或对象。 对象必须存在时传递引用。 在函数内部,被引用的参数意味着该值存在,但是在对其进行解引用之前必须检查空指针。 另外,通过引用,还可以保证目标对象是有效的。 指针可能指向一个无效的地址(不为空),并导致未定义的行为。

在语义上,引用确实充当地址。 但是,在语法上,它们是编译器的工作,而不是你自己的,你可以把引用看作是它指向的原始对象,包括绑定其他引用,并让它们引用原始对象。 在这种情况下告别指针算术。

其缺点是你不能修改它们所指的内容 – 它们在构build时绑定。