繁体   English   中英

C ++返回指针/引用

[英]C++ Returning Pointers/References

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

但是当我看到这样的东西时,我感到很困惑:

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被初始化为整数为Global。

有人可以验证我的所有四个问题是否正确?

虽然彼得回答了你的问题,但有一点让你感到困惑的是符号*& 有关获取你的头围绕这些最困难的部分是,它们都具有与间接做两个不同的含义(即使剔除的第三含义*乘法和&按位和)。

  • * ,当用作类型的一部分时,表示类型是指针: int是一个类型,因此int*是指向int的类型,而int**是指向指针到int类型的指针。

  • &当用作类型的一部分时表示该类型是引用。 int是一个类型,所以int&是一个引用到int(没有引用引用这样的东西)。 引用和指针用于类似的事情,但它们是完全不同的,不可互换。 最好将引用视为现有变量的别名或备用名称。 如果xint ,那么您可以简单地指定int& y = x来为x创建新名称y 后, xy可以互换使用,以指代相同的整数。 这样做的两个主要含义是引用不能为NULL(因为必须有一个原始变量来引用),并且您不需要使用任何特殊运算符来获取原始值(因为它只是一个替代名称,不是指针)。 引用也不能重新分配。

  • *当用作一元运算符时,执行称为解除引用的操作(与引用类型无关!)。 此操作仅对指针有意义。 当您取消引用指针时,您将返回它指向的内容。 因此,如果p是指向int的指针,则*p是指向的int

  • &用作一元运算符执行称为地址的操作时。 这是非常不言自明的; 如果x是一个变量,那么&x是的地址x 可以将变量的地址分配给指向该变量类型的指针。 因此,如果x是一个int ,则可以将&x分配给int*类型的指针,该指针将指向x 例如,如果指定int* p = &x ,则可以使用*p来检索x的值。

所以请记住,类型后缀&是引用,并没有任何与一元手术室& ,这与获得的地址,以指针的使用做。 这两种用途完全不相关。 *作为类型后缀声明指针,而*作为一元运算符执行指针操作。

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

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

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

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

在returnC()中,我要求返回一个int的地址。 当我返回c时,&运算符会自动附加吗?

不,它是对返回的int的引用。 引用不是与指针相同的地址 - 它只是变量的替代名称。 因此,您无需应用&运算符来获取变量的引用。

在returnC2()中,我再次询问要返回的int的地址。 * d是否有效,因为指针指向一个地址?

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

指针通常不指向一个地址(尽管它们可以 - 例如int**是指向int**的指针)。 指针某种东西的地址。 当您将指针声明为something* ,指针指向的something就是这样。 所以在上面的例子中, int**声明了一个指向int*的指针,它恰好是一个指针本身。

Tyler,这是非常有用的解释,我做了一些使用visual studio调试器的实验来进一步澄清这种差异: -

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).
}

在你的函数,变量j分配给指向a的临时位置。 退出函数后,变量a消失,但它的前一个位置是通过j返回的。 因为a不再存在于位置的指向j ,不确定的行为将与访问发生*j

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

作为迂腐,返回的指针应声明为指向常量数据。 返回的引用应该是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。 该函数返回对常量值的引用。 这意味着其他函数可以使用该值(来自远方),就好像它是一个变量(无需取消引用指针)。

在我看来,指针用于可选参数或对象。 当对象必须存在时传递引用。 在函数内部,引用的参数意味着该值存在,但是在解除引用之前必须检查指针是否为null。 此外,通过引用,可以更加保证目标对象有效。 指针可能指向无效的地址(非null)并导致未定义的行为。

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

这样做的缺点是你无法修改它们所指的内容 - 它们在构造时受到约束。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM