Am I understanding pointers and references correctly?

I'm trying to see if I have a basic understanding of pointers and references, so my apologies if I don't.

In example 1 and 2, I'm passing a reference of num. So I'm not copying data, I'm passing the memory address of num (in both examples), which I'm assuming is great for large objects.

When I printed num after calling test(), I noticed a difference: example 2 does not let me change the value. Are there any other differences, because they seem very similar aside from that only detail?

1
2
3
4
5
6
7
8
9
10
11
  // Example 1
  void test(int &num) {
     num += 5  
  }

  int main() {
     int num = 5;
     test(num);
     std::cout << num << "\n"; // returns 10
     return 0;
  }


and...

1
2
3
4
5
6
7
8
9
10
11
  // Example 2
  void test(int *num) {
     num += 5  
  }

  int main() {
     int num = 5;
     test(&num);
     std::cout << num << "\n"; // returns 5
     return 0;
  }
Last edited on
A reference is not a pointer (address). A reference is an alias.

When you change a reference to a value, you are changing the original value.
When you change a pointer to a value (the address), you are changing the pointer, not the pointed-to value.

If, in example 2, you want to add 5 to the num declared in the main function, you should write
1
2
3
void test(int *num) {
     *num += 5  
}

Where * is the dereference operator, which tells the computer to access/modify the pointed-to value.

You are correct in that you aren't copying the value of either `num' in either example; it is good for large objects. Note that passing a value by reference or pointer and not modifying can be surprising, so you should always mark your function parameters as const as possible.
Last edited on
@mbozzi thank you for your detailed answered. I understood this explanation better than the replies on Stack Overflow. I won't forget to mark my function parameters with const.

I do have one more question if you're still around and don't mind:

What if I have a class, and I want to store a reference to a struct in that class?

1
2
3
4
5
6
7
8
class Character {
public:
   Character(const Transform &position) {
       m_pos = position;
   }
private:
 Transform m_pos;
};


In this example, would I be saving a reference of the Transform I passed?
No, you'd be making a copy!
m_pos is a Transform, not a Transform&.

If you want to store a reference, you need to change the declaration of m_pos to be (line 7) Transform &m_pos;, but that's not all. Since references cannot be null, i.e., they always refer to a real object, they have to be initialized with a value.

Member objects and some other stuff is initialized before the code making up the constructor body is run. The constructor body is the stuff on line 4 of your example above. If you need to do something other than "default initialize" a member, you need to do so in the constructor initializer list.

The syntax looks like this:
1
2
3
4
5
6
7
8
9
class Character {
public: 
  Character(const Transform &position) 
    : m_pos(position) { 
    /* You don't need to do anything here: `m_pos' now refers to `position' */
  }
private:
  Transform &m_pos;
};


This problem is similar to what happens if you take your snippet above but mark m_pos const. You can't just assign to a constant value, but you can initialize it: this is the difference between calling an assignment operator in the constructor (m_pos = position) and actually initializing the value when it's constructed.

In other words, the difference is like that between
int const foo = 5; or int &baz = some_int; and
int const foo; foo = 5; /*oops! doesn't compile!*/ or int &baz; /*oops! doesn't compile!*/ baz=some_int;.

Edit:
Make sure the referred-to value exists the next time you use it. Once m_pos is initialized, nothing stops it from being destroyed and leaving this class with a "dangling reference".

The issue is that this class doesn't control the lifetime (doesn't "own") the value to which m_pos refers. Now it's the caller's problem to make sure that the referred-to value still exists.

At some point you should look into "smart pointers", which help enforce those ownership semantics and make things easier in general.
Last edited on
Thanks again @mbozzi, awesome answer. I've got a better understanding now :)
Last edited on
>> That is not true. ... *((int*)nullptr) ...

Dereferencing a null-pointer engenders undefined behaviour

undefined behaviour: Renders the entire program meaningless
http://en.cppreference.com/w/cpp/language/ub
Surely your memory fails you, gentleguy/NaughtyAlbatross/closed_account_5a8Ym39o6.


http://www.cplusplus.com/forum/beginner/195371/#msg940769
closed account (jN09E3v7)
0 to 123? I wonder if a 64 bit system gives a different answer to the *nullptr problem @gentleguy alerts us to. You would need to derefence it if you are checking for null as in a while loop eg while (!null) equivalent
Last edited on
Topic archived. No new replies allowed.