指针变量和引用变量之间的区别是什么?


当前回答

如果你不熟悉以抽象的甚至学术的方式学习计算机语言,那么语义上的差异可能会显得深奥难懂。

在最高级别上,引用的概念是它们是透明的“别名”。你的计算机可能会使用一个地址来使它们工作,但你不必担心:你应该将它们视为现有对象的“另一个名称”,语法反映了这一点。它们比指针更严格,因此编译器可以在您将要创建悬挂引用时比在您将创建悬挂指针时更可靠地警告您。

除此之外,指针和引用之间当然还有一些实际差异。使用它们的语法明显不同,您不能“重新定位”引用、引用虚无或引用指针。

其他回答

不同之处在于,非常量指针变量(不要与指向常量的指针混淆)可能会在程序执行过程中的某个时间发生更改,需要使用指针语义(&,*)运算符,而引用只能在初始化时设置(这就是为什么您只能在构造函数初始化器列表中设置它们,但不能以其他方式设置它们),并使用普通值访问语义。基本上,引用是为了支持运算符重载而引入的,正如我在一些非常古老的书中所读到的那样。正如有人在这个线程中所说的,指针可以设置为0或任何您想要的值。0(NULL,nullptr)表示指针初始化为空。取消引用空指针是错误的。但实际上,指针可能包含一个不指向某个正确内存位置的值。反过来,引用试图不允许用户初始化对某个无法引用的对象的引用,因为您总是向其提供正确类型的右值。尽管有很多方法可以将引用变量初始化到错误的内存位置,但最好不要深入了解细节。在机器级,指针和参考都通过指针统一工作。让我们假设在基本参考中是句法糖。rvalue引用与此不同,它们自然是堆栈/堆对象。

指针(*)的基本含义是“地址处的值”,这意味着您提供的任何地址都将在该地址处给出值。一旦你改变了地址,它将给出新的值,而引用变量用于引用任何特定的变量,将来不能改变为引用任何其他变量。

除非我需要以下任何一项,否则我会使用参考资料:

空指针可以用作哨兵价值,通常是一种廉价的方式避免函数重载或使用嘘声。你可以在指针上做算术。例如,p+=偏移量;

我对引用和指针有一个类比,将引用看作对象的另一个名称,将指针看作对象的地址。

// receives an alias of an int, an address of an int and an int value
public void my_function(int& a,int* b,int c){
    int d = 1; // declares an integer named d
    int &e = d; // declares that e is an alias of d
    // using either d or e will yield the same result as d and e name the same object
    int *f = e; // invalid, you are trying to place an object in an address
    // imagine writting your name in an address field 
    int *g = f; // writes an address to an address
    g = &d; // &d means get me the address of the object named d you could also
    // use &e as it is an alias of d and write it on g, which is an address so it's ok
}

可以重新分配指针: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&更便于在参数列表等中使用。