6

Possible Duplicate:
c++ * vs & in function declaration

I know that this probably seems like an incredibly elementary question to many of you, but I have genuinely had an impossible time finding a good, thorough explanation, despite all my best Googling. I'm certain that the answer is out there, and so my search terms must be terrible.

In C++, a variety of symbols and combinations thereof are used to mark parameters (as well as arguments to those parameters). What, exactly, are their meanings?

Ex: What is the difference between void func(int *var) and void func(int **var)? What about int &var?

The same question stands for return types, as well as arguments. What does int& func(int var) mean, as compared to int* func(int var)? And in arguments, how does y = func(*x) differ from y = func(&x)?

I am more than happy to read enormous volumes on the subject if only you could point me in the right direction. Also, I'm extremely familiar with general programming concepts: OO, generics/templates, etc., just not the notation used in C/C++.

EDIT: It seems I may have given the impression that I do not know what pointers are. I wonder how that could be :)

So for clarification: I understand perfectly how pointers work. What I am not grasping, and am weirdly unable to find answers to, is the meaning of, for example 'void func(int &var)'. In the case of an assignment statement, the '&' operator would be on the right hand side, as in 'int* x = &y;', but in the above, the '&' operator is effectively on the left hand side. In other words, it is operating on the l-value, rather than the r-value. This clearly cannot have the same meaning.

I hope that I'm making more sense now?

Community
  • 1
  • 1
burfl
  • 2,138
  • 2
  • 20
  • 18
  • 3
    Protip: C and C++ have very little in common. – Puppy Mar 09 '12 at 15:48
  • 2
    Time to re-read [your C++ book](http://jcatki.no-ip.org/fncpp/Resources). You cannot learn a programming language by grabbing at Google – Lightness Races in Orbit Mar 09 '12 at 15:52
  • These are pointers, read up on pointers and de-referencing pointers. I am sure if you google that instead of the symbols you will be more than happy with what you find. Ex http://www.cplusplus.com/doc/tutorial/pointers/ Which explains all the questions you had in your post. – jzworkman Mar 09 '12 at 15:52
  • 1
    @LightnessRacesinOrbit I humbly disagree. I have learned the vast majority of what I know about computer science and programming from various internet sources (not all Google, but generally found using it). I think that I'm going to clarify my question, because I understand pointers just fine... edit coming momentarily. – burfl Mar 09 '12 at 16:04
  • an templates are very different from generics – bames53 Mar 09 '12 at 16:06
  • 1
    @burfl: C++ is just one of those languages were you're in for trouble without a book. To solve your problem: It's called a reference. – Xeo Mar 09 '12 at 16:10
  • `In other words, it is operating on the l-value, rather than the r-value.` nonsense. However, it _is_ "operating on" (actually is part of) the type, rather than on an expression. _That's_ the difference. – Lightness Races in Orbit Mar 09 '12 at 16:13
  • 3
    Nooo! I spent 30 minutes writing a thorough response to this with specific answers to all subquestions, only to find out that the question had been closed. :( – Anders Sjöqvist Mar 09 '12 at 16:30
  • I don't think this question is a duplicate of that question at all. – bames53 Mar 09 '12 at 18:21
  • @bames53: I agree, though perhaps I'm biased. The linked question pertains to the choice between pointers and references, while mine pertains entirely to the notation. – burfl Mar 09 '12 at 18:40

5 Answers5

13

To understand this you'll first need to understand pointers and references. I'll simply explain the type declaration syntax you're asking about assuming you already know what pointers and references are.

In C, it is said that 'declaration follows use.' That means the syntax for declaring a variable mimics using the variable: generally in a declaration you'll have a base type like int or float followed something that looks like an expression. For example in int *y the base type is int and the expression look-alike is *y. Thereafter that expression evaluates to a value with the given base type.

So int *y means that later an expression *y is an int. That implies that y must be a pointer to an int. The same holds true for function parameters, and in fact for whole function declarations:

int *foo(int **bar);

In the above int **bar says **bar is an int, implying *bar is a pointer to an int, and bar is a pointer to a pointer to an int. It also declares that *foo(arg) will be an int (given arg of the appropriate type), implying that foo(arg) results in a pointer to an int.¹ So the whole function declaration reads "foo is a function taking a pointer to a pointer to an int, and returning a pointer to an int."

C++ adds the concept of references, and messes C style declarations up a little bit in the process. Because taking the address of a variable using the address-of operator & must result in a pointer, C doesn't have any use for & in declarations; int &x would mean &x is an int, implying that x is some type where taking the address of that type results in an int.² So because this syntax is unused, C++ appropriates it for a completely different purpose.

In C++ int &x means that x is a reference to an int. Using the variable does not involve any operator to 'dereference' the reference, so it doesn't matter that the reference declarator symbol clashes with the address-of operator. The same symbol means completely different things in the two contexts, and there is never a need to use one meaning in the context where the other is allowed.

So char &foo(int &a) declares a function taking a reference to an int and returning a reference to a char. func(&x) is an expression taking the address of x and passing it to func.


1. In fact in the original C syntax for declaring functions 'declarations follow use' was even more strictly followed. For example you'd declare a function as int foo(a,b) and the types of parameters were declared elsewhere, so that the declaration would look exactly like a use, without the extra typenames.

2. Of course int *&x; could make sense in that *&x could be an int, but C doesn't actually do that.

bames53
  • 86,085
  • 15
  • 179
  • 244
  • 3
    I wrote an awesome compliment for you here, but forgot to hit the 'Add Comment' button and can no longer remember exactly what I said. Very thorough, perfectly on-point, and incredibly helpful. You saw through my veil of naivete and identified the root cause of my confusion. – burfl Mar 09 '12 at 18:03
5

What you're asking about are called pointers (*), and reference to (&), which I think is best explained here.

ShadowScripter
  • 7,314
  • 4
  • 36
  • 54
  • +1 Coincidentally, I read that article yesterday. It's very well written. – karlphillip Mar 09 '12 at 15:53
  • 3
    Nothing is "best explained" on cplusplus.com. Nothing. – Lightness Races in Orbit Mar 09 '12 at 15:54
  • 1
    @karlphillip Yes, their [whole tutorial](http://www.cplusplus.com/doc/tutorial/) is a good read if you ask me! :3 – ShadowScripter Mar 09 '12 at 15:57
  • No, he's not asking about the address-of operator. He is asking about the use of `&` in a *declaration*, not an *expression*. In a declaration, that symbol specifies a "reference", which is unrelated to the address-of operator. – Robᵩ Mar 09 '12 at 16:13
  • @Rob You're right, in the context he's asking it is the "reference", but aren't you arguing over semantics at this point? Since the `&` is in fact an address to a variable. It is already explained in the link I provided. However, I will correct my answer to "reference to". – ShadowScripter Mar 09 '12 at 16:17
  • @ShadowScripter: Full of errors and bad advice. Avoid. – Lightness Races in Orbit Mar 09 '12 at 16:18
  • @ShadowScripter: The semantics are precisely important here. And, in fact, referring to a reference as "an address to a variable" is strictly inaccurate; a reference is a reference. – Lightness Races in Orbit Mar 09 '12 at 16:19
  • I've read cplusplus.com before and am not personally a fan. However, the reference material there is pretty good, considering I've found no other such reference on the 'net. Feel free to point me to better material if it exists. – burfl Mar 09 '12 at 18:50
  • @burfl I think I first learned about pointers and references from [`C++ A beginner's Guide by Herbert Schildt`](http://www.e-booksdirectory.com/details.php?ebook=3516) (It's free!. Page 88 is about pointers and references in general. Page 125 is about references and pointers in functions. Any ways, I recommend you read some of it), I don't know if it's good or not, but I found it pretty exhaustive, descriptive and explanatory. It all comes down to personal taste I guess. – ShadowScripter Mar 09 '12 at 19:17
2

The symbols & and * are used to denote a reference and pointer type, respectively.

int means simply the type 'int', int* means 'pointer to int', int& means 'reference to int',

A pointer is a variable which is used to store the address of a variable. A reference has the syntax of its base type, but the semantics of a pointer to that type. This means you don't need to dereference it in order to change the value.

To take an example, the following code blocks two are semantically equivalent:

int* a = &value;
*a = 0;

And:

int& a = value;
a = 0;

The main reasons to use pointers or references as an argument type is to avoid copying of objects and to be able to change the value of a passed argument. Both of these work because, when you pass by reference, only the address is copied, giving you access to the same memory location as was "passed" to the function.

In contrast, if a reference or pointer type is not used, a full copy of the argument will be made, and it is this copy which is available inside the function.

Agentlien
  • 4,996
  • 1
  • 16
  • 27
  • And lo, my elusive search terms manifest :D Thanks for this. Clearly, my problem was missing the meaning of '&' as applied to a type, rather than a value (int& a = value vs. int a = &value). I honestly didn't know the '&' operator could be used in this way. Now it makes perfect sense in parameters. – burfl Mar 09 '12 at 16:20
  • @burfl: FWIW it's not an operator at all in the former case – Lightness Races in Orbit Mar 09 '12 at 16:44
  • Fair enough. It's just a part of the type in this case, correct? – burfl Mar 09 '12 at 17:39
2

The symbols * and & have three meanings each in C++:

  1. When applied to an expression, they mean "dereference" and "address-of" respectively, as you know.

  2. When part of a type, they mean "pointer" and "reference", respectively.

    Since C++ doesn't care about arbitrary spacing, the declaration int *ptr is exactly the same as the declaration int* ptr, in which you can now more clearly see that this is an object called ptr of type int*.1

  3. When used between two expressions, they mean "multiply" and "bitwise AND", respectively.


1 - though, frustratingly, this isn't actually how the internal grammar reads it, thanks to the nasty legacy of C's type system. So avoid single-line multi-declarations involving pointers unless you want a surprise.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Thanks very much for this; it is very helpful, and I would upvote if I had the requisite rep. I know it's a bit tangent, but could you elaborate on your 'citation' at the bottom? How, specifically, would the compiler iterpret 'int* x, y z;' vs. 'int *x, y, *z;'? – burfl Mar 09 '12 at 17:42
  • The compiler would read the first as `int *x; int y; int z;` and the second as `int *x; int y; int *z;`. You have to explicitly note whether each variable is an `int` or a pointer to one. – chris Mar 25 '12 at 01:13
2

Ex: What is the difference between 'void func(int *var)' and 'void func(int **var)'? What about 'int &var'?

The same question stands for return types, as well as arguments. What does 'int& func(int var)' mean, as compared to 'int* func(int var)'? And in arguments, how does 'y = func(*x)' differ from '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; 
     }   
alkber
  • 1,426
  • 2
  • 20
  • 26