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


当前回答

塔林♦ 说:

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

事实上你可以。

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

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

其他回答

简单地说,我们可以说引用是变量的替代名称,指针是保存另一个变量地址的变量。例如

int a = 20;
int &r = a;
r = 40;  /* now the value of a is changed to 40 */

int b =20;
int *ptr;
ptr = &b;  /*assigns address of b to ptr not the value */

引用是另一个变量的别名,而指针保存变量的内存地址。引用通常用作函数参数,因此传递的对象不是副本而是对象本身。

    void fun(int &a, int &b); // A common usage of references.
    int a = 0;
    int &b = a; // b is an alias for a. Not so common to use. 

实际上,引用并不像指针。

编译器保持对变量的“引用”,将名称与内存地址相关联;这是编译时将任何变量名转换为内存地址的工作。

创建引用时,只告诉编译器为指针变量指定了另一个名称;这就是为什么引用不能“指向null”,因为变量不能是,也不能是。

指针是变量;它们包含其他变量的地址,或者可以为空。重要的是指针有一个值,而引用只有一个引用的变量。

现在对真实代码进行一些解释:

int a = 0;
int& b = a;

在这里,您没有创建另一个指向;您只需将另一个名称添加到内存内容中,该内存内容的值为a。该内存现在有两个名称,a和b,可以使用任一名称对其进行寻址。

void increment(int& n)
{
    n = n + 1;
}

int a;
increment(a);

当调用函数时,编译器通常为要复制到的参数生成内存空间。函数签名定义了应该创建的空间,并给出了应该用于这些空间的名称。将参数声明为引用只是告诉编译器使用输入变量内存空间,而不是在方法调用期间分配新的内存空间。说你的函数将直接操作在调用作用域中声明的变量似乎很奇怪,但请记住,在执行编译代码时,没有更多的作用域;只有普通的平面内存,函数代码可以处理任何变量。

现在,在某些情况下,编译器在编译时可能无法知道引用,例如使用外部变量时。因此,在底层代码中,引用可以实现为指针,也可以不实现为指针。但在我给你的例子中,它很可能不会用指针实现。

指针和引用之间有一个非常重要的非技术性区别:通过指针传递给函数的参数比通过非常量引用传递给函数参数的参数更为可见。例如:

void fn1(std::string s);
void fn2(const std::string& s);
void fn3(std::string& s);
void fn4(std::string* s);

void bar() {
    std::string x;
    fn1(x);  // Cannot modify x
    fn2(x);  // Cannot modify x (without const_cast)
    fn3(x);  // CAN modify x!
    fn4(&x); // Can modify x (but is obvious about it)
}

回到C中,一个看起来像fn(x)的调用只能通过值传递,因此它肯定不能修改x;要修改参数,需要传递指针fn(&x)。所以,如果一个参数前面没有&,你就知道它不会被修改。(相反,&表示已修改,这是不正确的,因为有时必须通过常量指针传递大型只读结构。)

一些人认为,这是读取代码时非常有用的特性,指针参数应该始终用于可修改的参数,而不是非常量引用,即使函数从不期望null指针。也就是说,这些人认为不应该允许像上面的fn3()这样的函数签名。谷歌的C++风格指南就是一个例子。

你忘记了最重要的部分:

带指针的成员访问使用->使用引用的成员访问。

foo.bar明显优于foo->bar,就像vi明显优于Emacs一样:-)