[英]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;
}
returnA()
我要求返回一个指针; 只是为了澄清这是有效的,因为j
是一个指针? returnB()
我要求返回一个指针; 因为指针指向一个地址, returnB()
工作的原因是因为我正在返回&b
? returnC()
我要求返回一个int
的地址。 当我返回c
, &
运算符会自动“追加” c
? returnC2()
我再次询问要返回的int
的地址。 *d
是否有效,因为指针指向一个地址? 假设a,b,c被初始化为整数为Global。
有人可以验证我的所有四个问题是否正确?
虽然彼得回答了你的问题,但有一点让你感到困惑的是符号*
和&
。 有关获取你的头围绕这些最困难的部分是,它们都具有与间接做两个不同的含义(即使剔除的第三含义*
乘法和&
按位和)。
*
,当用作类型的一部分时,表示类型是指针: int
是一个类型,因此int*
是指向int的类型,而int**
是指向指针到int类型的指针。
&
当用作类型的一部分时表示该类型是引用。 int
是一个类型,所以int&
是一个引用到int(没有引用引用这样的东西)。 引用和指针用于类似的事情,但它们是完全不同的,不可互换。 最好将引用视为现有变量的别名或备用名称。 如果x
是int
,那么您可以简单地指定int& y = x
来为x
创建新名称y
。 后, x
和y
可以互换使用,以指代相同的整数。 这样做的两个主要含义是引用不能为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.