C ++:函数/方法声明中的&符和星号“ *”之间的区别?


70

两者之间是否存在某种微妙的区别:

void a1(float &b) {
    b=1;
};
a1(b);

void a1(float *b) {
    (*b)=1;
};
a1(&b);

它们都执行相同的操作(或从main()看来),但是第一个显然较短,但是我看到的大多数代码都使用第二种表示法。有区别吗?也许是某些对象而不是float?


1
现在尝试找出void a1(float && b)在C ++ 0x中的含义。:)
丹尼尔·厄威克

最好也能解释为什么LHS&在某些情况下可能比*更可取,或者,如果我们有*作为参考,甚至根本没有必要。
T. Webster

@ T.Webster:引用是不可变的。这意味着当您创建一个对象时,它肯定引用了某个内容(因此不能为NULL,编译器会强制您明确指定要引用的内容),一旦创建该对象,就永远无法引用其他内容。它们比较安全,因为在您不打算这样做时,您不会意外地执行诸如指针算术之类的愚蠢的事情。
2013年


1
@Flow我认为这个问题应该保留,因为我一直在寻找这个确切的点,除非我访问过此页面,否则我不知道一个指向指针,另一个指向通过引用传递。不过,感谢您链接到另一个问题!
2015年

Answers:


56

两者都一样,但是一个使用引用,一个使用指针。

有关所有差异的完整列表,请参见此处的答案


1
也赞成,而不是我的“ -1”。也许有人觉得这还不够解释。感谢你的回答!
Slava V

很棒的帖子,现在已经挣扎了几个小时,阅读完您的摘要后,我得到了“尤里卡”的祝福;)感谢@DanielSloof!
polyclick 2012年

26
我想对此投下反对票,因为它不过是一个链接。关于SO的答案应该完全独立,链接被用作支持/参考,而不是整个答案。照原样,我不会对此投反对票,因为它指向了另一个SO答案,这使我将发布链接作为问题的大问题无效化了:网站多年来可能并且确实会发生变化或崩溃!但是,当然,如果一个答案不正确,那么另一个答案似乎也很可能,因此,我让它通过,并且不对其投票。
ArtOfWarfare 2013年

26

是。该*符号表示在栈上传递的是一个指针,即某物的地址。该&说这是一个参考。效果相似但不相同:

我们来看两种情况:

   void examP(int* ip);
   void examR(int& i);

   int i;

如果我打电话examP,我写

   examP(&i);

它获取项目的地址并将其传递到堆栈上。如果我打电话examR

   examR(i);

我不需要 现在,编译器“以某种方式”传递了一个引用-实际上意味着它获取并传递的地址i。在代码方面,然后

   void examP(int* ip){
        *ip += 1;
   }

我必须确保取消引用指针。 ip += 1做一些非常不同的事情。

   void examR(int& i){
        i += 1;
   }

总是更新的值i

要进一步考虑,请阅读“按引用调用”与“按值调用”。该&概念通过引用给出C ++调用。


查理·马丁(Charlie Martin)或了解此答案的人,请改写/重写为更简洁的答案?具体来说,这是两种示例情况。我相信这里有有价值的信息,并且我相信这个答案和用户将从更简洁的答案中受益。我自己编辑答案,但我不理解这两个示例案例。
HappyCoding

我认为您最好阅读Stroustrup。我不怪你困惑。
查理·马丁

5

在带有引用的第一个示例中,您知道b不能为NULL。对于指针示例,b可能是NULL指针。

但是,请注意,这可以通过引用传递一个空对象,但它的尴尬和被调用过程可以认为这是一个错误已经这样做了:

a1(*(float *)NULL);

3

在第二个示例中,调用者必须在变量名前添加“&”,以传递变量的地址。

这可能是一个优点-调用者在认为变量是按值传递时,不能无意中通过将变量作为引用传递来修改变量。


3

除了语法糖之外,唯一真正的区别是作为指针的函数参数为null的能力。因此,如果指针版本可以正确处理null大小写,则其指针版本可以更具表现力。空值案例还可以具有一些特殊的含义。参考版本只能在没有null功能的情况下对指定类型的值进行操作。


1

在您的示例中,两个版本的功能相同。

第一个优点是在调用方是透明的。想象一下它将如何寻找运营商:

cin >> &x;

以及交换调用的外观如何丑陋

swap(&a, &b);

您要交换a和b。它看起来比您初次使用地址时要好得多。顺便说一句,bjarne stroustrup写道,引用的主要原因是在调用方增加了透明度-特别是对于操作员。还要看看下面的内容是否不再明显

&a + 10

会将10加到a的内容中,调用它的operator +,或者是否将10加到指向a的临时指针中。再加上不可能只对内置操作数(如指针和整数)不能重载运算符的可能性。参考文献使这一点很清楚。

如果您希望能够放置“ null”,则指针非常有用:

a1(0);

然后在a1中,该方法可以将指针与0比较,并查看指针是否指向任何对象。


swap(int&a,int&b)无法确定是否使用相同的参数进行了调用:swap(x,x); 早点跳出来 指针版本可以:if(a == b)返回;不确定是否重要,但是在某些情况下参考版本无法处理。
jmucchiello

乔,它可以:if(&a ==&b)return;
Johannes Schaub-litb

0

值得注意的一大区别是外面发生了什么,您要么有:

a1(something);

要么:

a1(&something);

我喜欢在未在函数/方法中修改参数时通过引用传递参数(始终为const one :))(然后您也可以在内部传递自动/临时对象),并通过指针传递参数以表示和警告用户/该参数的读者可能会在内部有意地修改该参数的方法。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.