Thread: Confusion with * and &

  1. #1
    myNegReal
    Join Date
    Jun 2005
    Posts
    100

    Confusion with * and &

    I know what a pointer is and how to use it, and also pass it through function parameters. And I recently found out about references they're called? For example:
    Code:
    int& ref = some_variable;
    It's similar to a pointer, but not as useful, but doesn't need to be dereferenced. Other than that, why would you use it instead of a pointer?
    Also, I've seen this, which is really confusing me: int*& var, for example, usually as a function parameter. What does *& mean? What is it doing or taking as a parameter. Also, usually when I see it, a normal variable is being passed into the function. And when assigned a value, it's assinged the memory address of. I'm confused what this is and what's happening. Any idea? Also, when assigned this memory address, it's usually of a pointer to an array or struct. The memory of a value in the array or a struct is the value assigned.
    A sample code:
    Code:
    int* an_array = new int[10];
    int an_int;
    some_function(an_array, an_int);
    // Or would you pass &an_int or something? I've never actually
    // seen the function call, I just know that the variable to be
    // passed was a normal variable.
    
    void some_function(int* array, int*& something) {
         something = &array[1];
    }

  2. #2
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    Why use references. Usually they are used either for efficiency, so you do not have to pass large objects or pointers about. Sometimes they are used to bind the lifetime of a temporary. In general they are easier and safer to use than pointers. There are many reasons for using references and as you become more familiar with c++ you will find even more uses for them.
    Now onto your second question ....
    what is....

    int*& var;

    It helps to read declarations like this backwards. This says that var is a reference(&) to a pointer(*) to an int. So This is how you pass a pointer by reference. It is similar to passing a double pointer in C so that you may change the value of the pointer itself and have the changes reflected into the calling function.
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  3. #3
    FOX
    Join Date
    May 2005
    Posts
    188
    > Usually they are used either for efficiency, so you do not have to pass large objects or pointers about.

    How is passing a pointer instead of a reference less effecient? I've always thought about references as disguised constant pointers (but with some advanced usage with classes), so wouldn't an reference to an int variable and a pointer to an int variable generate the exact same machine code?

  4. #4
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    It usually isnt but it is more open to mistakes.pointers are easily misused and in a lot of cases can be replaced by references.
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  5. #5
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    Code:
    It's similar to a pointer, but not as useful...
    Why isn't a reference as useful? Some of the most experienced people on this forum advocate using references instead of pointers.

    [a reference] doesn't need to be dereferenced. Other than that, why would you use it instead of a pointer?
    The syntax is simpler. For instance,
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    };
    
    void changeIt(Apple& anApple)
    {
    	anApple.num = 30;
    }
    
    int main()
    {
    	Apple myApple;
    	myApple.num = 10;
    
    	changeIt(myApple);
    	cout<<myApple.num<<endl;  //30
    
    	return 0;
    }
    All I had to do was put a '&' symbol in the parameter name, and I could "pass by reference" and change the original object in main(). Especially note that I didn't have to declare an extra pointer variable and assign it the address of myApple, and then pass the pointer to the function.

    Also, I've seen this, which is really confusing me: int*& var, for example, usually as a function parameter. What does *& mean?
    That notation gets to the very essence of what "passing by value" and "passing by reference" really mean. You could say there is really no such thing as "passing by reference" and everything is "passed by value", by which I mean to say that all function parameters are passed the same way--they are copied for the function. Typically, C++ texts will make a big point of the differences between "passing by value" and "passing by reference". They will give an example of "passing by value" similar to this:
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    };
    
    void changeIt(Apple anApple)
    {
    	anApple.num = 30;
    }
    
    int main()
    {
    	Apple myApple;
    	myApple.num = 10;
    
    	changeIt(myApple);
    	cout<<myApple.num<<endl;  //10
    
    	return 0;
    }
    C++ texts will explain that when you pass myApple to the function, a copy of myApple is made for the function and stored in the function parameter variable anApple. Then, the function changes anApple which is just a copy of myApple, which leaves the original myApple unchanged. Therefore, the function isn't able to change the original object.

    However, the C++ texts will say that if you "pass by reference", then the original object isn't copied, so the function can change the original object. For instance,
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    };
    
    void changeIt(Apple* aPtr)
    {
    	aPtr->num = 30; 
    }
    
    int main()
    {
    	Apple myApple;
    	myApple.num = 10;
    	
    	Apple* myPtr = &myApple;
    	changeIt(myPtr);
    	cout<<myApple.num<<endl;  //30
    
    	return 0;
    }
    It's true that the function can permanently change the object, however when you send a pointer to a function, why would the original object ever get copied? The original object was never sent as an argument to the function. The fact of the matter is: the pointer is the argument being sent to the function, and just like when you send an object to a function, the pointer is copied for the function. So, the function gets a copy of the pointer, and since a copy of a pointer points to the same place as the original pointer, the function can use the pointer to change the object. As the example above shows, the object reflects the changes made by the function.

    Ok, so now that you know a copy of the original pointer is made for the function, what happens if instead of changing the object, you want the function to be able to change the pointer, i.e. assign it another address? Well, you're in the same predicament as when you send an object to a function: the function cannot change the original pointer because all it has is a copy of the pointer. Here is an example:
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    };
    
    void changeIt(Apple* ptr1, Apple* ptr2)
    {
    	ptr1 = ptr2; 
    }
    
    int main()
    {
    	Apple myApple;
    	myApple.num = 10;
    	Apple* myPtr = &myApple;
    	cout<<myPtr->num<<endl; //10
    	
    	Apple yourApple;
    	yourApple.num = 30;
    	Apple* yourPtr = &yourApple;
    
    	changeIt(myPtr, yourPtr);
    	cout<<myPtr->num<<endl; //10
    
    	return 0;
    }
    The example shows that the function was unable to change the pointer myPtr that was passed to the function. After calling the function, myPtr still points to the same object. However, there is a way to solve that problem. The solution is identical to when you have an object and you use pointers to "pass by reference", so the function can change the object. In this case, if you think of myPtr as the object you are passing to the function, how can you enable the function to make changes to that object? The answer is: you pass a pointer to the object--which means you can pass a pointer to myPtr. Your function parameters would look like this:

    void changeIt(myPtr* ptr1, Apple* ptr2)

    But, myPtr isn't a type, so you can't list it as one. myPtr is of type Apple*, so substituting you get:

    void changeIt(Apple* *ptr1, Apple* ptr2)

    Here is a complete example:
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    };
    
    void changeIt(Apple* *ptr1, Apple* ptr2)
    {
    	*ptr1 = ptr2; 
    	
    }
    
    int main()
    {
    	Apple myApple;
    	myApple.num = 10;
    	Apple* myPtr = &myApple;
    	Apple* *ptr = &myPtr;
    	cout<<(*ptr)->num<<endl; //10
    	
    	Apple yourApple;
    	yourApple.num = 30;
    	Apple* yourPtr = &yourApple;
    
    
    	changeIt(ptr, yourPtr);
    	cout<<(*ptr)->num<<endl; //30
    
    	return 0;
    }
    The notation is pretty tortured and confusing, but here is an explanation. In the function, dereferencing ptr1 gets you an Apple pointer, which points to myApple. If the function was able to change the 'ptr' variable that was sent as an argument, then back in main(), ptr should hold the address of the function parameter ptr2. But, ptr2 is a copy of yourPtr, and a copy of yourPtr and yourPtr hold the same address. Since ptr was assigned ptr2, ptr should hold the address of yourPtr. In turn, yourPtr holds the address of yourApple. So, back in main(), you should end up with:

    ptr------>yourPtr---->yourApple

    The output shows that was the case.

    Since references are nearly equivalent to pointers, you are able to accomplish the same thing as the last example with much cleaner syntax:
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    };
    
    void changeIt(Apple* &ptr1, Apple* ptr2)
    {
    	ptr1 = ptr2; 
    	
    }
    
    int main()
    {
    	Apple myApple;
    	myApple.num = 10;
    	Apple* myPtr = &myApple;
    	cout<<myPtr->num<<endl; //10
    	
    	Apple yourApple;
    	yourApple.num = 30;
    	Apple* yourPtr = &yourApple;
    
    
    	changeIt(myPtr, yourPtr);
    	cout<<myPtr->num<<endl; //30
    
    	return 0;
    }
    As you can see, the syntax is much less tortured than when pointers were used.
    Last edited by 7stud; 06-21-2005 at 05:11 AM.

  6. #6
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    One characteristic of pointers is that thay can be NULL (i.e. not point at anything). When a pointer is given to a function, it either has to test that pointer or assume it is non-NULL. Pointers can also be reassigned.

    References can only be assigned when they are created, and using any unitialised reference or initialising a reference using a non-existant objhect yields undefined behaviour. One consequence of this is that a function, when given a reference, is allowed to assume it references a valid object. As most code creates some objects, but pass them to many functions, not having to do this test every time an object is used results in a performance gain (and less scope for the programmer to accidentally do something invalid).

  7. #7
    Anti-Poster
    Join Date
    Feb 2002
    Posts
    1,401
    Quote Originally Posted by grumpy
    One characteristic of pointers is that thay can be NULL (i.e. not point at anything).
    Quoted for emphasis. This makes pointers very useful for optional parameters. When creating a function, I usually use references (or plain "pass-by-value") for required parameters and pointers for optional parameters.
    If I did your homework for you, then you might pass your class without learning how to write a program like this. Then you might graduate and get your degree without learning how to write a program like this. You might become a professional programmer without knowing how to write a program like this. Someday you might work on a project with me without knowing how to write a program like this. Then I would have to do you serious bodily harm. - Jack Klein

  8. #8
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    References can only be assigned when they are created
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    };
    
    void changeIt(Apple* ptr1, Apple* ptr2)
    {
    	ptr1 = ptr2; 
    }
    
    int main()
    {
    	
    	Apple myApple;
    	myApple.num = 10;
    
    	Apple yourApple;
    	yourApple.num = 30;
    
    	Apple ref = myApple;
    	cout<<ref.num<<endl;
    
    	ref = yourApple;
    	cout<<ref.num<<endl;
    
    	return 0;
    }

  9. #9
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    ref is an Apple not an Apple&. Its not a reference its an object.

    If you changed it to this.....
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    };
    
    int main()
    {
    	
    	Apple myApple;
    	myApple.num = 10;
    
    	Apple yourApple;
    	yourApple.num = 30;
    
    	Apple& ref = myApple;
    	cout<<ref.num<<endl;
    
    	ref = yourApple;
    	cout<<ref.num<<endl;
    	return 0;
    }
    Then what exactly do you think this line does here:-
    Code:
    ref = yourApple;
    Last edited by Stoned_Coder; 06-21-2005 at 11:38 AM.
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  10. #10
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    I think yourApple is copied into myApple:
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    	
    	Apple() {};
    
    	Apple& operator=(const Apple& anApple)
    	{
    		cout<<"assignment operator called"<<endl;
    		
    		num = anApple.num;
    		return *this;
    	}
    };
    
    int main()
    {
    	
    	Apple myApple;
    	myApple.num = 10;
    
    	Apple yourApple;
    	yourApple.num = 30;
    
    	Apple& ref = myApple;
    	cout<<ref.num<<endl;
    
    	ref = yourApple;
    	cout<<ref.num<<endl;
    
    
    	return 0;
    }
    In other words, a constant pointer cannot change the address it points to but what's at that address can be changed.
    Last edited by 7stud; 06-21-2005 at 12:02 PM.

  11. #11
    Skunkmeister Stoned_Coder's Avatar
    Join Date
    Aug 2001
    Posts
    2,572
    Is exactly right. Big gold star for 7stud. References cannot be changed once set. An attempt to change one like above results in an assignment to the aliased object.
    Free the weed!! Class B to class C is not good enough!!
    And the FAQ is here :- http://faq.cprogramming.com/cgi-bin/smartfaq.cgi

  12. #12
    myNegReal
    Join Date
    Jun 2005
    Posts
    100
    Wow, really helpful guys, I understand more about pointers and references, and I didn't know pointers got copied, I thought it just passed the memory address. But now I see that it still copies, but it works, because it points to the same thing. Thanks a lot. Just one thing though..

    Quote Originally Posted by 7stud
    I think yourApple is copied into myApple:
    Code:
    #include <iostream>
    using namespace std;
    
    class Apple
    {
    public:
    	int num;
    	
    	Apple() {};
    
    Apple& operator=(const Apple& anApple)
    	{
    		cout<<"assignment operator called"<<endl;
    		
    		num = anApple.num;
    		return *this;
    	}
    };
    
    int main()
    {
    	
    	Apple myApple;
    	myApple.num = 10;
    
    	Apple yourApple;
    	yourApple.num = 30;
    
    	Apple& ref = myApple;
    	cout<<ref.num<<endl;
    
    	ref = yourApple;
    	cout<<ref.num<<endl;
    
    
    	return 0;
    }
    In other words, a constant pointer cannot change the address it points to but what's at that address can be changed.
    Can you explain what's going on there? It looks like a reference is being assigned to a function? And the const Apple& anApple, does the variable passed into a function or otherwise that takes a const need to be const itself? Or does it make the copy a const within the function?
    Last edited by Ganoosh; 06-21-2005 at 04:49 PM.

  13. #13
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Whoa, choose better colours next time.

    Do you mean this line?
    Code:
    Apple& operator=(const Apple& anApple)
    The operator= part of it I mean.

  14. #14
    myNegReal
    Join Date
    Jun 2005
    Posts
    100
    Lol, I fixed the colors, sorry about that, must've been bright I guess. Yes, that line and the rest of the code in the brackets following. I assume it belongs to that statement, being you can't just have brackets floating.

  15. #15
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
    Apple& operator=(const Apple& anApple) {
        cout<<"assignment operator called"<<endl;
    		
        num = anApple.num;
        return *this;
    }
    This overloads the = operator. So every time = is used on class Apple, this function is called.

Popular pages Recent additions subscribe to a feed