各种符号(*,&等)与参数组合的区别是什么?

6
可能与以下问题重复:
c++ * vs & in function declaration 我知道这对许多人来说可能是一个非常基础的问题,但是即使在我最好的谷歌搜索中,我真的无法找到一个好的、详尽的解释。我相信答案在那里,所以我的搜索术肯定很糟糕。
在C++中,各种符号及其组合用于标记参数(以及这些参数的参数)。它们的确切含义是什么呢?
例如: void func(int *var)和void func(int **var)之间有什么区别?int &var呢?
对于返回类型以及参数,同样的问题存在。int& func(int var)与int* func(int var)有什么区别?在参数中,y = func(*x)与y = func(&x)有什么不同?
如果只能指出正确的方向,我就非常愿意阅读大量关于这个主题的资料。此外,我对一般的编程概念:OO、generics/templates等非常熟悉,只是不熟悉C/C++中使用的符号。
编辑: 看起来我可能给人留下了我不知道指针是什么的印象。我不知道怎么会这样 :)
所以为了澄清:我完全理解指针的工作原理。我没有掌握的是,例如 'void func(int &var)' 的含义。在赋值语句的情况下,'&' 操作符将位于右手边,如 'int* x = &y',但是在上述代码中,'&' 操作符实际上位于左手边。换句话说,它对 l-value 起作用,而不是 r-value。这显然不能有相同的含义。
希望现在我表达得更清楚些。

3
专业提示:C和C++几乎没有什么共同之处。 - Puppy
2
是时候重新阅读你的 C++ 书籍了。你不能通过在 Google 上搜索来学习编程语言。 - Lightness Races in Orbit
1
@LightnessRacesinOrbit 我不太同意。我从各种互联网资源(不全是谷歌,但通常是通过谷歌找到的)中学到了我所知道的计算机科学和编程的绝大部分内容。我认为我将澄清我的问题,因为我很好地理解指针...编辑即将到来。 - burfl
1
@burfl:C++是那种没有书籍就会陷入麻烦的语言之一。解决问题的方法:参考手册。 - Xeo
3
不!我花了30分钟时间撰写了一份详尽的回答,针对所有子问题都提供了具体答案,结果发现问题已经关闭了。:( - Anders Sjöqvist
显示剩余5条评论
5个回答

13
为了理解这个问题,首先需要理解指针和引用。我将简要解释你所问的类型声明语法,假设你已经知道指针和引用是什么。
在 C 语言中,有一个概念叫做“先声明后使用”。这意味着声明变量的语法类似于使用变量的语法:通常在声明中,你会有一个基本类型,比如 intfloat,后面跟着一些看起来像表达式的东西。例如,在 int *y 中,基本类型是 int,而类似于表达式的部分是 *y。然后,该表达式将评估为具有给定基本类型的值。
因此,int *y 表示稍后表达式 *y 是一个 int。这意味着 y 必须是一个指向整数的指针。对于函数参数以及整个函数声明,同样适用此规则。
int *foo(int **bar);
以上的代码中,int **bar 表示 **bar 是一个 int 类型,意味着 *bar 是指向一个 int 类型的指针,而 bar 是指向一个指向 int 类型的指针的指针。同时,它还声明了 *foo(arg) 将是一个 int 类型(给定适当类型的 arg),这意味着 foo(arg) 的结果将是一个指向 int 类型的指针。因此,整个函数声明的含义是“foo 是一个接受指向指向 int 类型的指针的指针的指针的函数,并返回一个指向 int 类型的指针”。
C++ 引入了引用的概念,并在此过程中略微混乱了 C 风格的声明。由于使用取地址运算符 & 获取变量的地址必须导致指针,C 在声明中没有使用 & 的任何用途;int &x 会意味着 &x 是一个 int 类型,这意味着 x 是某种类型,其中获取该类型的地址会导致 int 类型。因此,因为这种语法未使用,C++ 将其占用于完全不同的目的。
在 C++ 中,int &x 意味着 x 是一个 int 的引用。使用变量不涉及任何操作符来“解引用”引用,因此引用声明符符号与取地址运算符之间的冲突不重要。同一符号在两个上下文中具有完全不同的含义,在允许使用另一种含义的上下文中从未需要使用其中一种含义。
因此,char &foo(int &a) 声明了一个函数,该函数接受一个 int 的引用并返回一个 char 的引用。 func(&x) 是一个表达式,它获取 x 的地址并将其传递给 func

3
我曾在此为你写下了一则极棒的赞扬,但是忘记点击“添加评论”按钮,现在无法准确回忆起当时的内容。那则评论非常详尽、准确无误,而且帮助极大。你看透了我天真无邪的掩饰,发现了我困惑的根源。 - burfl

5
您所询问的是指针(*)和引用(&),我认为最好在这里进行解释。

+1 好巧,我昨天刚读了那篇文章。写得非常好。 - karlphillip
3
在cplusplus.com上没有任何东西可以被称为“最好的解释”。没有。 - Lightness Races in Orbit
1
@karlphillip 是的,他们的整个教程在我看来都很好!:3 - ShadowScripter
不,他不是在问取地址运算符。他在询问在声明中使用&,而不是表达式。在声明中,该符号指定了一个“引用”,与取地址运算符无关。 - Robᵩ
@Rob 你说得对,在他问的这种情况下,确实是“引用”,但你现在争论的不是语义吗?因为 & 实际上是一个变量的地址。我已经在我提供的链接中解释过了。然而,我会纠正我的回答为“指向引用”。 - ShadowScripter
显示剩余4条评论

2
符号 & 和 * 分别用于表示引用和指针类型。
int 表示简单的 int 类型, int* 表示指向 int 的指针, int& 表示 int 的引用。
指针是用于存储变量地址的变量。 引用具有其基础类型的语法,但具有指向该类型的指针的语义。这意味着您无需解引用即可更改值。
举个例子,以下代码块两者在语义上等价:
int* a = &value;
*a = 0;

同时:

int& a = value;
a = 0;

使用指针或引用作为参数类型的主要原因是避免对象的复制并能够更改传递参数的值。这两个原因都是因为当你通过引用传递时,只有地址被复制,从而使你可以访问与函数“传递”的相同内存位置。

相反,如果不使用引用或指针类型,则会进行参数的完全复制,并且在函数内部可用的是这个副本。


嗨,我的搜索术语终于出现了 :D 谢谢你提供这个。显然,我的问题在于没有理解'&'作用于类型而不是值的含义(int& a = value与int a = &value之间的区别)。老实说,我真的不知道'&'运算符可以以这种方式使用。现在,在参数中使用它完全有意义了。 - burfl
@burfl:就我所知,在前一种情况下根本不是一个运算符。 - Lightness Races in Orbit
好的。在这种情况下,这只是类型的一部分,对吧? - burfl

2

例如:'void func(int *var)' 和 'void func(int **var)' 之间有什么区别?那么 'int &var' 呢?

同样的问题也适用于返回类型和参数。'int& func(int var)' 相较于 'int* func(int var)' 有什么不同?在参数方面,'y = func(*x)' 和 'y = func(&x)' 有何区别?

(1)
    <return type> <function name> <parameters> 
    void           func            (int *var) 

    <parameter> here int *var is a pointer to integer, ie it can point to 
    an array or any buffer that should be handled with integer pointer 
    arithmetic. In simple terms , var holds the address of the respective 
    **actual parameter.**

    eg: int arr[10]; 
        func(arr);

        int a = 33;
        func(&a);

        Here, &a means we are explicitly passing address of the the variable 'a'. 
 (2) 
     int m = 0; 
     int &var = m;

     Here var means reference, ie it another alias name for variable 'm' , 
     so any change 'var' makes will change the contents of variable 'm'.

     var = 2; /* will change the actual contents of 'm' */ 

     This simple example will not make sense , unless you understand the context. 
     Reference are usually use to pass parameter to function, so that changes made by 
     the function to the passed variable is visible at the caller.

     int swap(int &m, int &n) {
         tmp = m;
         m = n; 
         n = tmp; 
     }   

     void main( void ) {

        int x = 1, y = 2;
        swap(x, y);
        /* x = 2, y =1 */   

     }

(3) 
     'int& func(int var)' mean, as compared to 'int* func(int var)'?

      int& func(int var) means the function returns a reference; 
      int* func(int var) means the function returns a pointer / address; 

      Both of the them has its context; 


      int& setNext() {

            return next;   
      } 

      setNext() = previous; 


      where as 

      int* setNext() {

           return &next; 
      } 

      int *inptr;
      inptr = setNext(); 
      *inptr = previous;

      In the previous two lines, 

      int *inptr <- integer pointer declaration; 
      *inptr <- means we are accessing contents of the address pointed by inptr; 
      ie we are actually referring to 'next' variable. 

      The actual use is context specific. It can't be generalized.  

(4) 
    how does 'y = func(*x)' differ from 'y = func(&x)'?                           

     y = func(&x) is already explained. 

     y = func(*x) , well i'm not sure if you actually meant *x.


     int swap(int *m, int *n) {
         tmp = *m;
         *m = *n; 
         *n = tmp; 
     }   

又一个出色的答案。感谢您提供的所有示例!非常有帮助。 - burfl
你介意点个赞吗 :) 作为感激之情 ;-) - alkber
非常想这样做,但是由于声望值小于15,我显然无法做到:( - burfl

2
符号*&在C++中各有三种含义:
  1. 当应用于表达式时,它们分别表示“解引用”和“取地址”,如您所知。

  2. 当作为类型的一部分时,它们分别表示“指针”和“引用”。

    由于C++不关心任意空格,声明int *ptr与声明int* ptr完全相同,在后者中,您现在可以更清楚地看到这是一个名为ptr的对象,其类型为int*1

  3. 当用于两个表达式之间时,它们分别表示“乘法”和“按位与”。


1 - 尽管令人沮丧的是,这实际上并不是内部语法的读法,这要归因于C类型系统的恶劣遗留问题。因此,除非您想要惊喜,否则请避免涉及指针的单行多声明。


非常感谢这个答案,它非常有帮助。如果我有足够的声望,我会点赞的。我知道这有点离题,但是您能详细说明一下底部的“引用”吗?具体来说,编译器如何解释“int * x, y z;”与“int *x, y, *z;”之间的区别? - burfl
编译器将第一个读作 int *x; int y; int z;,第二个读作 int *x; int y; int *z;。每个变量是 int 还是指向其的指针都必须明确注明。 - chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接