C ++返回指针/引用

时间:2010-05-14 20:05:11

标签: c++ pointers return

我对解除引用运算符,运算符地址和一般指针有相当好的理解。

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

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是否有效,因为指针指向一个地址?
  5. 假设a,b,c被初始化为整数。

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

6 个答案:

答案 0 :(得分:72)

虽然彼得回答了你的问题,但有一点让你感到困惑的是符号*&。了解这些问题的难点在于它们都有两个与间接有关的不同含义(甚至不包括乘法的*的第三含义和按位的&和。) / p>

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

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

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

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

请记住,类型后缀&用于引用,与一元操作&无关,后者与获取指针使用的地址有关。这两种用途完全不相关。 *作为类型后缀声明一个指针,而*作为一元运算符对指针执行操作。

答案 1 :(得分:27)

  

在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*的指针,它恰好是指针本身。

答案 2 :(得分:5)

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

答案 3 :(得分:2)

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

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

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

答案 4 :(得分:2)

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

让我澄清一下:

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。此外,通过引用,可以更加保证目标对象有效。指针可能指向无效的地址(非空)并导致未定义的行为。

答案 5 :(得分:1)

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

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