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


当前回答

如果你真的想变得迂腐,有一件事你可以用指针做,但不能用指针做:延长临时对象的生命周期。在C++中,如果将常量引用绑定到临时对象,则该对象的生存期将变为引用的生存期。

std::string s1 = "123";
std::string s2 = "456";

std::string s3_copy = s1 + s2;
const std::string& s3_reference = s1 + s2;

在本例中,s3_copy复制连接后的临时对象。而s3_reference本质上成为临时对象。它实际上是对临时对象的引用,该对象现在与引用具有相同的生存期。

如果您尝试在没有常量的情况下执行此操作,它将无法编译。不能将非常量引用绑定到临时对象,也不能为此获取其地址。

其他回答

为了避免混淆,我想输入一些输入,我确信这主要取决于编译器如何实现引用,但在gcc的情况下,引用只能指向堆栈上的变量的想法实际上并不正确,例如:

#include <iostream>
int main(int argc, char** argv) {
    // Create a string on the heap
    std::string *str_ptr = new std::string("THIS IS A STRING");
    // Dereference the string on the heap, and assign it to the reference
    std::string &str_ref = *str_ptr;
    // Not even a compiler warning! At least with gcc
    // Now lets try to print it's value!
    std::cout << str_ref << std::endl;
    // It works! Now lets print and compare actual memory addresses
    std::cout << str_ptr << " : " << &str_ref << std::endl;
    // Exactly the same, now remember to free the memory on the heap
    delete str_ptr;
}

其输出如下:

THIS IS A STRING
0xbb2070 : 0xbb2070

如果您注意到甚至内存地址都完全相同,这意味着引用成功地指向了堆上的一个变量!现在,如果你真的想变得古怪,这也很有效:

int main(int argc, char** argv) {
    // In the actual new declaration let immediately de-reference and assign it to the reference
    std::string &str_ref = *(new std::string("THIS IS A STRING"));
    // Once again, it works! (at least in gcc)
    std::cout << str_ref;
    // Once again it prints fine, however we have no pointer to the heap allocation, right? So how do we free the space we just ignorantly created?
    delete &str_ref;
    /*And, it works, because we are taking the memory address that the reference is
    storing, and deleting it, which is all a pointer is doing, just we have to specify
    the address with '&' whereas a pointer does that implicitly, this is sort of like
    calling delete &(*str_ptr); (which also compiles and runs fine).*/
}

其输出如下:

THIS IS A STRING

因此,引用是引擎盖下的指针,它们都只是存储一个内存地址,地址指向的位置是不相关的,如果我调用std::cout<<str_ref;调用delete str_ref后?很明显,它编译得很好,但在运行时会导致分段错误,因为它不再指向有效变量,我们本质上有一个中断的引用仍然存在(直到它超出范围),但没有用。

换句话说,引用只是一个指针,它抽象了指针机制,使其更安全、更容易使用(没有意外的指针数学,没有混淆“.”和“->”等),假设您没有像上面的例子那样尝试任何废话;)

现在,不管编译器如何处理引用,它总是有某种指针,因为引用必须引用特定内存地址处的特定变量,才能按预期工作,因此无法绕过这一点(因此称为“引用”)。

对于引用,唯一需要记住的重要规则是必须在声明时定义它们(头中的引用除外,在这种情况下,必须在构造函数中定义引用,在构造包含引用的对象之后,再定义它就太晚了)。

请记住,我上面的例子只是说明引用是什么的例子,你永远不想以这些方式使用引用!为了正确使用参考文献,这里已经有很多答案,这些答案一针见血

如果遵循传递给函数的参数的约定,则可以使用引用和指针之间的差异。Const引用用于传递到函数中的数据,指针用于传递出函数的数据。在其他语言中,您可以使用诸如In和out之类的关键字来明确表示这一点。在C++中,您可以(按照约定)声明等价的。例如

void DoSomething(const Foo& thisIsAnInput, Foo* thisIsAnOutput)
{
   if (thisIsAnOuput)
      *thisIsAnOutput = thisIsAnInput;
}

使用引用作为输入和指针作为输出是Google风格指南的一部分。

塔林♦ 说:

不能像使用指针那样获取引用的地址。

事实上你可以。

我引用了另一个问题的答案:

C++常见问题解答说得最好:与指针不同,一旦引用绑定到对象,就不能将其“重新放置”到另一个对象。引用本身不是一个对象(它没有标识;获取引用的地址可以获得引用的地址;记住:引用是它的引用)。

这个程序可能有助于理解问题的答案。这是一个引用“j”和指向变量“x”的指针“ptr”的简单程序。

#include<iostream>

using namespace std;

int main()
{
int *ptr=0, x=9; // pointer and variable declaration
ptr=&x; // pointer to variable "x"
int & j=x; // reference declaration; reference to variable "x"

cout << "x=" << x << endl;

cout << "&x=" << &x << endl;

cout << "j=" << j << endl;

cout << "&j=" << &j << endl;

cout << "*ptr=" << *ptr << endl;

cout << "ptr=" << ptr << endl;

cout << "&ptr=" << &ptr << endl;
    getch();
}

运行程序并查看输出,您就会明白。

另外,抽出10分钟观看以下视频:https://www.youtube.com/watch?v=rlJrrGV0iOg

简言之

指针:指针是保存另一个变量的内存地址的变量。指针需要使用*运算符解引用以访问它所指向的内存位置。-摘自Geeks for Geeks

引用:引用变量是别名,即现有变量的另一个名称。引用(如指针)也通过存储对象的地址来实现。-摘自极客对极客

另一张图片了解更多详情: