指向引用的指针,指针引用和指向C ++中指针的指针有什么区别?
哪一方优先于另一方?
答案 0 :(得分:52)
首先,对指针的引用就像对任何其他变量的引用:
void fun(int*& ref_to_ptr)
{
ref_to_ptr = 0; // set the "passed" pointer to 0
// if the pointer is not passed by ref,
// then only the copy(parameter) you received is set to 0,
// but the original pointer(outside the function) is not affected.
}
指向引用的指针在C ++中是非法的,因为-unlike指针 - 引用只是一个允许程序员创建其他东西的别名的概念。指针是内存中的位置,其地址为其他内容,但引用不是。
现在最后一点可能不是很清楚,如果你坚持将引用作为指针处理。 e.g:
int x;
int& rx = x; // from now on, rx is just like x.
// Unlike pointers, refs are not real objects in memory.
int* p = &x; // Ok
int* pr = ℞ // OK! but remember that rx is just x!
// i.e. rx is not something that exists alone, it has to refer to something else.
if( p == pr ) // true!
{ ... }
从上面的代码中可以看出,当我们使用引用时,我们不会处理与它所引用的内容分离的内容。因此,引用的地址只是它所引用的地址。这就是为什么没有这样的东西称为你正在谈论的参考地址。
答案 1 :(得分:42)
C ++中的指针只是一个存储内存位置的值(通常为32位值)。
假设您有一个用户输入整数值(十六进制为78
== 0x4E
)。
它将以与此类似的方式存储在内存中(我故意简化此示例中的内容):
Memory address Value
0x12345678 0x0000004E
如果你想创建一个指向这个值的“指针”,它在内存中会是这样的:
Memory address Value
0x22334455 0x12345678
在内存地址0x22334455
,您现在有一个“指针”,其值为0x12345678
,或者存储用户输入整数值(0x4E
)的内存地址。
假设您想要为此指针值创建一个“指针”。它看起来像这样:
Memory address Value
0x11335577 0x22334455
你现在在内存中有一个新的“指针”值,它存储了先前定义的指针值的内存地址。
可以无限制地创建指针 - 关键是要记住指针只是编译器解释为内存位置的另一个值(并且它提供了各种访问语义,例如*
和->
这对于“指针”类型来说是特殊的。)
引用可以被视为另一个真实对象的视图或别名。当您创建对名为myReference
的指针的引用时,您只需定义一个名为myReference
的新名称,该名称可用于访问您之前在内存中定义的指针。
在内部,引用是使用指针实现的,但这超出了你的问题的范围。
引用对C ++中的其他类型有限制 - 例如,必须在创建时始终初始化引用“引用”真实对象,而指针可能 em>指向无效或未初始化的内存。
这不存在。如前所述,引用仅仅是另一个对象的别名。你不能“指向”一个引用,因为它本身不是一个对象,而只是一个真实对象的另一个名称。
当然,您可以使用指向引用引用的对象的指针。但现在我们回到了香草指针领域。
将参数按值传递给方法或例程时,实质上是将对象的“副本”传递给方法。例程返回时,对例程中的值所做的任何更改都将丢失,因为该参数将在例程的上下文中被视为局部变量。
如果要修改传入的参数以便客户端(调用)代码可以访问更改,则必须通过指针或引用传递参数
例如:
void myMethod(int myValue)
{
// NOTE: This change will be lost to the caller!
myValue = 5;
}
void myMethod2(int* myValue)
{
// Correct way of modifying pointer parameter value
*myValue = 5;
}
void myMethod3(int& myValue)
{
// Correct way of modifying reference parameter value
myValue = 5;
}
现在让我们说你的方法想要为指针分配内存。你可能会想要这样做:
void myMethod4(int* myValue)
{
// Warning: You will lose the address of the allocated
// memory when you return!
myValue = new int[5];
}
但请记住,您正在修改指针值的 copy ,而不是 real 指针值。由于您希望修改此例程中的指针,而不是指针“指向”的值,因此您需要将其作为“指针指向”指针“或”对指针的引用“:
void myMethod5(int** myValue)
{
// Correct way of allocating memory in a method
// via pointer-to-pointer
*myValue = new int[5];
}
void myMethod6(int*& myValue)
{
// Correct way of allocating memory in a method
// via reference-to-pointer
myValue = new int[5];
}
在这两个底部的示例中,调用myMethod5
和myMethod6
的代码将通过myValue
参数指针或引用正确获取新分配的内存的内存地址。 / p>
答案 2 :(得分:10)
没有指向引用的指针。
答案 3 :(得分:5)
引用是远离指针的抽象。参考文献有点难以搞定,特别是对于新手来说,并且有点高级。
您没有需要引用。你总是可以使用指针。但是,有时代码可以更容易阅读。
典型的初学者示例是链接列表。想象一下,你有一个名为“list”的变量,它包含指向第一个的指针。如果你想在头部添加一些东西,你需要给你的add()一个双指针,因为它需要能够修改“head”。但是,您可以使用对指针的引用。在这里,我们想要在列表中使用指针,因为我们将改变它们,但是如果我们传入对列表头部的引用而不是双指针,则add()函数会更清晰。
他们只是一种风格选择。如果您正在开发一个更大的项目,那么您应该采用项目的风格。如果没有,你可以使用你认为更好的任何东西。但是,如果你希望成为一个温和成功的C ++程序员,你应该习惯使用所有样式。
您也不能拥有指向引用的指针。这是因为引用实际上只是另一个变量的另一个名称,可能在其他一些范围内。指向引用的指针没有意义。你真正想要的只是指向原始数据的指针,不涉及任何参考。
答案 4 :(得分:4)
值得注意的是,虽然引用不是对象,因此没有可访问的地址,但引用可以包含在对象中,而包含的对象也有地址。
struct contains_ref
{
int& ref;
contains_ref(int& target) : ref(target) {}
};
“引用是别名”解释不正确,但通常伴随着误导性声明。引用不等同于原始对象。它有自己的生命周期,由包含它的范围或对象决定,而不是它所引用的对象。引用可以比对象更长,并用于引用在同一地址创建的新对象。
将引用视为实际内容 - 围绕指针的抽象,将null排除为有效值,并防止重新安装 1 - 而不是魔法。引用的唯一不寻常的属性不是从它的指针性质派生出来的是临时性的终身扩展。
1 实际上,这是因为C ++没有提供任何语法来引用引用本身而不是它的目标。所有运算符(包括赋值运算符)都只是应用于目标。
答案 5 :(得分:0)
试着亲自看看每个人拿着什么。示例程序只打印int的值和不同实体的地址:
#include<stdio.h>
int main(){
int myInt ;
int *ptr_to_myInt = &myInt;
int *ptr_to_myInt_ref = ptr_to_myInt;
myInt = 42;
printf("myInt is %d\n",myInt);
printf("ptr_to_myInt is %x\n",ptr_to_myInt);
printf("ptr_to_myInt_ref is %x\n",ptr_to_myInt_ref);
printf("&ptr_to_myInt is %x\n",&ptr_to_myInt);
return 0;
}
输出:
myInt is 42
ptr_to_myInt is bffff858
ptr_to_myInt_ref is bffff858
&ptr_to_myInt is bffff854
因此,指向int的指针和指向int引用的指针完全相同。这在代码中是显而易见的,因为指向引用的指针只是别名指针的另一种方式(它说“为我保留以下地址”)。
现在,指针在内存中也需要一些空间,如果你打印对这个指针的引用(最后一个printf语句),它只是指示指针所在的内存中的位置。