指针变量和引用变量之间的区别是什么?
当前回答
简言之
指针:指针是保存另一个变量的内存地址的变量。指针需要使用*运算符解引用以访问它所指向的内存位置。-摘自Geeks for Geeks
引用:引用变量是别名,即现有变量的另一个名称。引用(如指针)也通过存储对象的地址来实现。-摘自极客对极客
另一张图片了解更多详情:
其他回答
塔林♦ 说:
不能像使用指针那样获取引用的地址。
事实上你可以。
我引用了另一个问题的答案:
C++常见问题解答说得最好:与指针不同,一旦引用绑定到对象,就不能将其“重新放置”到另一个对象。引用本身不是一个对象(它没有标识;获取引用的地址可以获得引用的地址;记住:引用是它的引用)。
引用的另一个有趣用法是提供用户定义类型的默认参数:
class UDT
{
public:
UDT() : val_d(33) {};
UDT(int val) : val_d(val) {};
virtual ~UDT() {};
private:
int val_d;
};
class UDT_Derived : public UDT
{
public:
UDT_Derived() : UDT() {};
virtual ~UDT_Derived() {};
};
class Behavior
{
public:
Behavior(
const UDT &udt = UDT()
) {};
};
int main()
{
Behavior b; // take default
UDT u(88);
Behavior c(u);
UDT_Derived ud;
Behavior d(ud);
return 1;
}
默认风格使用引用的“bind const reference to a temporary”方面。
“我知道引用是语法糖,所以代码更容易读写”
这引用不是实现指针的另一种方式,尽管它涵盖了大量的指针用例。指针是一种数据类型——通常指向实际值的地址。然而,它可以设置为零,或者使用地址算术等设置在地址之后的几个位置。对于具有自己值的变量,引用是“语法糖”。
C只有传递值语义。获取变量引用的数据的地址并将其发送到函数是一种通过“引用”传递的方法。引用通过“引用”原始数据位置本身在语义上简化了这一过程。因此:
int x = 1;
int *y = &x;
int &z = x;
Y是一个int指针,指向存储x的位置。X和Z表示相同的存储位置(堆栈或堆)。
很多人谈论过这两个(指针和引用)之间的区别,好像它们是同一个东西,用法不同一样。它们完全不同。
1) “指针可以被重新分配任意次数,而引用在绑定后不能被重新分配。”--指针是指向数据的地址数据类型。引用是数据的另一个名称。因此,您可以“重新分配”引用。你不能重新分配它所指的数据位置。就像你不能更改“x”所指的位置一样,你也不能更改“z”。
x = 2;
*y = 2;
z = 2;
相同的。这是一次重新分配。
2) “指针不能指向任何地方(NULL),而引用总是指向对象”——同样令人困惑。引用只是对象的另一个名称。空指针表示(语义上)它没有引用任何内容,而引用是通过表示它是“x”的另一个名称来创建的。自从
3) “你不能像用指针那样获取引用的地址”——是的,你可以。再次带着困惑。如果您试图查找用作引用的指针的地址,这是一个问题——因为引用不是指向对象的指针。他们就是目标。所以你可以得到对象的地址,也可以得到指针的地址。因为它们都在获取数据的地址(一个是对象在内存中的位置,另一个是指向对象在内存位置的指针)。
int *yz = &z; -- legal
int **yy = &y; -- legal
int *yx = &x; -- legal; notice how this looks like the z example. x and z are equivalent.
4) “这里没有“引用算术”——同样有点混淆——因为上面的例子中z是对x的引用,因此两者都是整数,所以“引用”算术意味着例如将x引用的值加1。
x++;
z++;
*y++; // what people assume is happening behind the scenes, but isn't. it would produce the same results in this example.
*(y++); // this one adds to the pointer, and then dereferences it. It makes sense that a pointer datatype (an address) can be incremented. Just like an int can be incremented.
关于引用和指针的一些关键相关细节
指针
使用一元后缀声明符运算符声明指针变量*指针对象被分配一个地址值,例如,通过分配给数组对象、使用一元前缀运算符的对象地址或分配给另一个指针对象的值指针可以重新分配任意次数,指向不同的对象指针是保存指定地址的变量。它占用的内存存储量等于目标机器体系结构的地址大小例如,可以通过增量或加法运算符对指针进行数学操作。因此,可以使用指针等进行迭代。要获取或设置指针引用的对象的内容,必须使用一元前缀运算符*来取消引用它
工具书类
引用在声明时必须初始化。引用使用一元后缀声明符运算符&声明。初始化引用时,可以使用它们将直接引用的对象的名称,而不需要一元前缀运算符&一旦初始化,引用就不能通过赋值或算术操作指向其他对象无需取消引用该引用以获取或设置其引用的对象的内容对引用的赋值操作操作它指向的对象的内容(初始化后),而不是引用本身(不改变它指向的位置)对引用的算术运算操作它指向的对象的内容,而不是引用本身(不会改变它指向的位置)在几乎所有的实现中,引用实际上都存储为被引用对象的内存中的地址。因此,它占用的内存大小与目标机器体系结构的地址大小相同,就像指针对象一样
尽管指针和引用的实现方式几乎相同,但编译器对它们的处理方式不同,导致了上述所有差异。
文章
我最近写的一篇文章比我在这里展示的要详细得多,对这个问题非常有帮助,特别是关于记忆中的事情是如何发生的:
数组、指针和引擎罩下的引用深度文章
可以重新分配指针:int x=5;整数y=6;int*p;p=&x;p=&y;*p=10;断言(x==5);断言(y==10);引用不能重新绑定,必须在初始化时绑定:int x=5;整数y=6;整数&q;//错误int&r=x;指针变量有它自己的标识:一个独特的、可见的内存地址,可以用一元&运算符获取,还有一定的空间,可以用sizeof运算符测量。对引用使用这些运算符将返回与引用绑定到的任何对象相对应的值;引用自身的地址和大小是不可见的。由于引用以这种方式假定原始变量的身份,因此可以方便地将引用视为同一变量的另一个名称。int x=0;int&r=x;int*p=&x;int*p2=&r;断言(p==p2);//&x==&r断言(&p!=&p2);可以将任意嵌套的指针指向提供额外间接级别的指针。引用仅提供一个间接级别。int x=0;整数y=0;int*p=&x;int*q=&y;int**pp=&p;**pp=2;pp=&q;//*pp现在是q**pp=4;断言(y==4);断言(x==2);指针可以指定为nullptr,而引用必须绑定到现有对象。如果您足够努力,您可以将引用绑定到nullptr,但这是未定义的,并且行为不一致。/*以下代码未定义;你的编译器可以优化它*不同的是,发出警告,或者干脆拒绝编译*/int&r=*static_cast<int*>(nullptr);//在GCC 10下打印“空”标准::cout<<(&r!=空指针? “not null”:“null”)<<std::endl;bool f(int&r){return&r!=nullptr;}//根据GCC 10打印“非空”标准::cout<<(f(*static_cast<int*>(nullptr))? “not null”:“null”)<<std::endl;但是,可以引用值为nullptr的指针。指针可以遍历数组;您可以使用++转到指针指向的下一个项目,使用+4转到第五个元素。这与指针指向的对象的大小无关。指针需要用*解引用以访问它指向的内存位置,而引用可以直接使用。指向类/结构的指针使用->访问其成员,而引用使用。。引用不能放入数组,而指针可以(由用户@litb提及)Const引用可以绑定到临时项。指针不能(不是没有间接指向):常量int&x=int(12);//法定C++int*y=&int(12);//取临时地址是非法的。这使得const&更便于在参数列表等中使用。