How reference share the memory address - c++

i was reading what is difference b/w pointer variable and reference variable in c++ here's. i got a point from that whereas a reference shares the same memory address but also takes up some space on the stack..
what does it mean that it share the same address space.please clear the how reference has been implemented in c++.

That's a somewhat confusingly-worded answer. But it means something rather simple. The part about taking up stack space just means a reference actually takes up memory. Namely, it takes up the same amount of memory that a pointer does (and in every C++ implementation [that I'm aware of] it's implemented by using an actual pointer).
The part about "share the same memory address" really means that a reference is not an independently-addressable value. If you have a pointer to something, you can take the address of that pointer and end up with a pointer to a pointer to something. But if you have a reference to something, you cannot take the address of that reference. Attempting to do so actually takes the address of the thing being referred to. That is what he means by "shares the same memory address".

Roghly speaking, a reference variable is like a pointer variable that does not look like a pointer (i.e. no pointer syntax for accessing the content). That does not have to do anything with Stack or Heap.
int i = 5; // integer on the Stack
int * j = new int (5); // integer on the Heap (accessible through pointer, naturally)
int & iref = i; // reference to integer on the Stack
int & jref = *j; // reference to integer on the Heap
int * ipointer = & i; // pointer to integer on the Stack
int * jpointer = j; // pointer to integer on the Heap

Related

How to change the address a pointer is pointing to in C++

While experimenting with pointers, I had the idea to change the address a pointer. I tried the following:
int* pointer;
&pointer = 0x28ff0d; //To point to an empty space in memory
But that threw out an error (Details: (here) in line 2, lvalue required as left operand [...]), so I guess it's impossible? I'm not trying to make a nullpointer, but litterally to change the memory address
For obvious reasons, setting a pointer to a hardcoded address is a bad idea. But, you can do so by reinterpret_cast<>ing the address to the type you're assigning it to, like so:
int * pointer = reinterpret_cast<int *>(0xDEADBEEF);
or
int * pointer = &some_int;
. . .
pointer = reinterpret_cast<int *>(0xDEADBEEF);
Note that dereferencing pointer in this case is undefined behavior... but doing this might still be useful for something like debugging a use-after-free, where a sentinel value like 0xDEADBEEF would clearly communicate that you had already freed that memory.
Obviously the much more common, useful, and safe case for changing the address you are pointing to would be to take the address of a different (real) piece of data:
int * pointer = &some_int;
int new_val = 1234;
pointer = &new_val; // *pointer is now 1234
You can never change the address of a variable. So whatever T is (be it an intrinsic type like int or double, a struct, a pointer or an array, the following is forbidden in C++:
T var;
&var = anything; // WRONG! &var is not a lvalue
The error lvalue required as left operand means that you can only assign to something that can receive a new value, and the address of a variable is not.
A pointer is a variable. Any variable has an address where it's located. So if you've declared a varible like e.g. int x;, then &x is the address where that variable resides.
A pointer is a variable which resides somewhere, but in addition it has a value, which happens to be an address of some other variable. So if you've declared a pointer int* x;, have written something to it, then x will represent some address you've written to it, and *x will be the value pointed to by the pointer.
So your syntactic mistake was using & where you should have just used the variable name, without &. After this is clear, be sure to read the other answers which explain further problems with your code.
int* pointer;
&pointer = 0x28ff0d;
This will throw error because &pointer is not an lvalue. On the left side of the assignment operator there must be an lvalue.

Difference between pointer declaration and indirection

I'm reading a book and I have doubts about what each of these syntax does. The first three lines I can understand but the following do not. Thank you very much if you help me, Julieta
int m; //m is int variable
int *p; //Pointer p pointing to an integer value
p=&m //The memory address of the variable m is assigned to p
float *longitud;
longitud=&cable1;
*longitud=40.5;
The concepts of value, pointer, and reference often trip people up, especially as they are often taught to look at them in terms of implementation and not in terms of the language.
A value is a thing that exists and has meaning. It always has a type (a constraint on its meaning) like int, float, char, and vector<string>.
An object is a value that exists somewhere in memory. (And not, say, mangled into a machine instruction code or produced on-the-fly in some way. That is, I could take out my memory chip and stick my finger on it, were my fingers nimble enough.)
A reference is an alias — a name for an object. The name is convenient for us as programmers. How the compiler maintains that name does not really matter. All that matters (language perspective!) is that if you have a name, you have direct access to an object.
To put that into perspective, whenever you name an object, you obtain a direct reference to that object. You can manipulate that object directly using its name.
A pointer is a value. Its type is a location in the computer’s memory of some object. With this location, I can gain access to the object’s value. In other words, I can use a pointer to gain a direct reference to an object.
Vocabulary + time = fickle understandings and encourage people to ask useless things2. Let’s clean our minds up a little.
First, a pointer is not a reference, it is an indirect reference. In order to get an actual, or direct, reference to a pointed-to object, we “dereference” the pointer. In other words, we perform a magic that transforms a pointer value to obtain a reference to an object.
The mechanics of how a pointer works are typically framed in terms of how the underlying hardware does something like “follows a pointer to a value”. We draw pictures with arrows and everything. We seem to forget to ask how this magic works. No one asks how variable names work either, but it is the exact same kind of magic. We simply trust when told “the compiler takes care of it”.
What is missed is the distinction between a (direct) reference (an alias or name for an object) and an indirect reference (a pointer or other thing that can be used to obtain a reference to an object).
Before C++ the difference between direct and indirect references really only made sense in the context of a pointer, and it was easy to call a pointer “a reference” instead of the full phrase “an indirect reference”, and so the vocabulary words mixed around in our heads, and we began to misunderstand the actual concepts involved.
Enter C++, stage left. We now have things called “references” in addition to pointers. In terms of the language, they are true aliases for other objects1.
To put it to example:
int x = 7; // "x" is a reference to the integer object with value 7
int& y = x; // "y" is a reference to the same integer object as "x".
int* p = // "p" is a pointer object whose value is an
// indirect reference to some integer object:
&x; // The & operator obtains an indirect reference (or pointer value) to "x"
And here is the last point. There are more than one meaning for "&"!
When attached to a type, it means that the type is a direct reference to some object
When attached to an object, it means that an indirect reference to that object is obtained
1 In C++, the abstraction leaks, because the lifetime of an object is bound only to the original reference. But that’s neither here nor there. There are other topics that deal with that here at SO.
2 So, to answer everyone’s favorite question: is a reference a pointer or not? The answer is, it doesn’t matter. (Unless you are writing a compiler.) You are asking implementation details about magic used to maintain a language-level concept. So sometimes it may be an actual pointer, sometimes it may simply be another entry in the compiler’s local symbol table, and it may even be something else if the compiler writer thinks it useful and appropriate.
3Language gets to be fuzzy. I had previously said "p" is a pointer. Technically, it is an object whose value is a pointer type. We can usually get away by just saying what type of thing an object is, though, and be well-understood. It is only when we are splitting hairs (in context) that the vocabulary needs more care, as it does here.
longitude is a pointer to a float variable
longitud=&cable1 assigns the address of cable1 (presumably a float?) to longitud, which now references cable1.
*longitud=40.5 dereferences longitude and assign it value 40.5. Because longitud references cable1, this assigns the value to cable1. That is *longitud and cable1 are the same thing.
None of this really relates to the question title "Difference between pointer declaration and indirection" - indirection is a general computing concept, and pointers are the means by which indirection is effected in C and C++.
Suppose you add one more (different) line in each section:
int m; // m is int variable
int *p; // pointer p is pointing to an integer value
p = &m; // the memory address of m is assigned to p
*p = 42; // ADDED: assign 42 to m, where p points to
float cable1; // ADDED: the variable where longitud points
float *longitud; // pointer longitud is pointing to a float value
longitud = &cable1; // the memory address of cable1 is assigned to longitud
*longitud = 40.5f; // assign 40.5 to cable1, where longitud points to
This completes the similar examples, which use different variable types.
After executing the lines
float cable1; // ADDED: the variable where longitud points
float *longitud; // pointer longitud is pointing to a float value
longitud = &cable1; // the memory address of cable1 is assigned to longitud
the following conditions are true:
longitude == &cable1
*longitude == cable1
IOW, the expression *longitud is equivalent to the expression cable1. So when you write
*longitud = 40.5f;
this is equivalent to writing
cable1 = 40.5f;
The * operator dereferences the longitud pointer, such that the expression *longitud evaluates to the same thing as cable1.
Cable1 needs to have a place memory before longitud can point to it.
The first 3 lines do this:
Set aside memory for an int.
Create an int pointer.
Get the int pointer to point at the int's memory address. Pointer references int.
The second 3 lines do this:
Create a float pointer.
Get the float pointer to point to a nonexistent address.
Try to assign a float value to that address.
If on line 4 you wrote:
float cable1;
You would have set aside memory and everything would work fine.
On the topic, you mean pointer declaration and dereferencing. I can give a short set of examples, though it mostly takes reading and practice to learn. Try these out and get a feel.
float f = 22.2f; //sets aside memory for a float with the name "f", stores 22.2
float *pf; //declares a float pointer.
pf = &f; //sets pf to point to f's memory address. pf references p.
printf("%f", *pf); //prints the value at the referenced address (22.2)
printf("%x", pf); //prints the memory address of the pointer itself
*pf = 33.3f; //changes the value at f's address to 33.3 (from 22.2)
f = 44.4f; //changes the value at f's address to 44.4 (from 33.3)
float *pf2;
*pf2 = 33.3 //BAD. pf2 is not assigned to an address, no value to change.
*pf2 = f; //BAD. pf2 has no memory address to copy the value to.
*pf2 = pf; //BAD. several reasons.
pf2 = pf; //pf2 now points to f's address, too.
pf2 = &f; //redundant. Same as the last line.
*pf2 = 55.5 //f has changed to 55.5. both pf2 and pf point to it.
Just think of the * as standing for "pointer" when you declare. When you use * later, it means "dereference." Dereferencing a pointer means you want to look at/use/change the referenced value. Later on, you'll learn that pointers can point to other pointers. So the value of a (char **) type is type (char *), rather than type (char).
If you don't have a book, I recommend C Programming - A Modern Approach 2nd Edition. It's a little dated but an excellent way to learn the fundamentals.

Static vs dynamic allocation of a pointer which stores just one int

I wonder why I would need the second version?
int* p; // version 1
int* p = new int; // version 2
In the first version, the pointer isn't pointing at anything, it is undefined. Version 2 allocated memory and points p to that new memory. You are not allocating space for the pointer itself but memory for the pointer to point at. (In both versions the pointer itself is on the stack)
Assuming that the code appears in a function:
The first one defines a local variable of type int* (that is, a pointer). The variable is not initialized, which means the pointer doesn't have a value. It doesn't point at anything. It's nearly useless, about the only thing you can do with it is assign a pointer value to it[*]. So you think to yourself, "can I hold off defining the variable until I have a value to assign to it?"
The second one defines a local variable of type int* (that is a pointer), and also dynamically allocates an object of type int and assigns the address of that object to the pointer variable. So the pointer points to the int.
Dynamically allocating one int is nearly always a bad idea. It's not useless in the sense that you do at least have an int and a means to access it. But you've created a problem for yourself in that you have to keep track of it and free it.
[*] other things you can do with an uninitialized int* variable: take the address of the variable; bind it to a reference of type int*&; convert the address of the variable to char* and examine the memory one byte at a time, just to see what your implementation has put in that uninitialized variable. Nothing exciting and, crucially, nothing involving any int objects because you have none.
The first pointer
The first pointer, declared as:
int* p;
only allocates the memory needed to to store a pointer to int. The actual size is implementation defined. What the p object contains is indeterminate as per 8.5/12:
If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced (5.17).
This means that dereferencing the pointer will lead to undefined behavior.
The second pointer
The second pointer, declared as:
int* p = new int;
dynamically allocates an int. This means that the lifetime of the object will terminate either at the exit of the program (not sure if the standard actually enforces this, but I'm pretty sure the underlying OS will take back the unused memory once the program is done executing) or when you free it.
This pointer can be dereferenced safely, unless operator new failed to allocate memory (in which case it will throw std::bad_alloc or, since C++11, another exception derived from std::bad_alloc).
Why the second pointer shouldn't be used in most cases
Memory management is an hard topic. The main tip that I can give you, is to avoid new and delete like a plague. Whenever you can do something in any other standard way, you should prefer it.
For example, in this case, the only reason I can come up with to justify such a technique is to have an optional parameter. You could, and should, std::optional instead.

What does "dereferencing" a pointer mean?

Please include an example with the explanation.
Reviewing the basic terminology
It's usually good enough - unless you're programming assembly - to envisage a pointer containing a numeric memory address, with 1 referring to the second byte in the process's memory, 2 the third, 3 the fourth and so on....
What happened to 0 and the first byte? Well, we'll get to that later - see null pointers below.
For a more accurate definition of what pointers store, and how memory and addresses relate, see "More about memory addresses, and why you probably don't need to know" at the end of this answer.
When you want to access the data/value in the memory that the pointer points to - the contents of the address with that numerical index - then you dereference the pointer.
Different computer languages have different notations to tell the compiler or interpreter that you're now interested in the pointed-to object's (current) value - I focus below on C and C++.
A pointer scenario
Consider in C, given a pointer such as p below...
const char* p = "abc";
...four bytes with the numerical values used to encode the letters 'a', 'b', 'c', and a 0 byte to denote the end of the textual data, are stored somewhere in memory and the numerical address of that data is stored in p. This way C encodes text in memory is known as ASCIIZ.
For example, if the string literal happened to be at address 0x1000 and p a 32-bit pointer at 0x2000, the memory content would be:
Memory Address (hex) Variable name Contents
1000 'a' == 97 (ASCII)
1001 'b' == 98
1002 'c' == 99
1003 0
...
2000-2003 p 1000 hex
Note that there is no variable name/identifier for address 0x1000, but we can indirectly refer to the string literal using a pointer storing its address: p.
Dereferencing the pointer
To refer to the characters p points to, we dereference p using one of these notations (again, for C):
assert(*p == 'a'); // The first character at address p will be 'a'
assert(p[1] == 'b'); // p[1] actually dereferences a pointer created by adding
// p and 1 times the size of the things to which p points:
// In this case they're char which are 1 byte in C...
assert(*(p + 1) == 'b'); // Another notation for p[1]
You can also move pointers through the pointed-to data, dereferencing them as you go:
++p; // Increment p so it's now 0x1001
assert(*p == 'b'); // p == 0x1001 which is where the 'b' is...
If you have some data that can be written to, then you can do things like this:
int x = 2;
int* p_x = &x; // Put the address of the x variable into the pointer p_x
*p_x = 4; // Change the memory at the address in p_x to be 4
assert(x == 4); // Check x is now 4
Above, you must have known at compile time that you would need a variable called x, and the code asks the compiler to arrange where it should be stored, ensuring the address will be available via &x.
Dereferencing and accessing a structure data member
In C, if you have a variable that is a pointer to a structure with data members, you can access those members using the -> dereferencing operator:
typedef struct X { int i_; double d_; } X;
X x;
X* p = &x;
p->d_ = 3.14159; // Dereference and access data member x.d_
(*p).d_ *= -1; // Another equivalent notation for accessing x.d_
Multi-byte data types
To use a pointer, a computer program also needs some insight into the type of data that is being pointed at - if that data type needs more than one byte to represent, then the pointer normally points to the lowest-numbered byte in the data.
So, looking at a slightly more complex example:
double sizes[] = { 10.3, 13.4, 11.2, 19.4 };
double* p = sizes;
assert(p[0] == 10.3); // Knows to look at all the bytes in the first double value
assert(p[1] == 13.4); // Actually looks at bytes from address p + 1 * sizeof(double)
// (sizeof(double) is almost always eight bytes)
++p; // Advance p by sizeof(double)
assert(*p == 13.4); // The double at memory beginning at address p has value 13.4
*(p + 2) = 29.8; // Change sizes[3] from 19.4 to 29.8
// Note earlier ++p and + 2 here => sizes[3]
Pointers to dynamically allocated memory
Sometimes you don't know how much memory you'll need until your program is running and sees what data is thrown at it... then you can dynamically allocate memory using malloc. It is common practice to store the address in a pointer...
int* p = (int*)malloc(sizeof(int)); // Get some memory somewhere...
*p = 10; // Dereference the pointer to the memory, then write a value in
fn(*p); // Call a function, passing it the value at address p
(*p) += 3; // Change the value, adding 3 to it
free(p); // Release the memory back to the heap allocation library
In C++, memory allocation is normally done with the new operator, and deallocation with delete:
int* p = new int(10); // Memory for one int with initial value 10
delete p;
p = new int[10]; // Memory for ten ints with unspecified initial value
delete[] p;
p = new int[10](); // Memory for ten ints that are value initialised (to 0)
delete[] p;
See also C++ smart pointers below.
Losing and leaking addresses
Often a pointer may be the only indication of where some data or buffer exists in memory. If ongoing use of that data/buffer is needed, or the ability to call free() or delete to avoid leaking the memory, then the programmer must operate on a copy of the pointer...
const char* p = asprintf("name: %s", name); // Common but non-Standard printf-on-heap
// Replace non-printable characters with underscores....
for (const char* q = p; *q; ++q)
if (!isprint(*q))
*q = '_';
printf("%s\n", p); // Only q was modified
free(p);
...or carefully orchestrate reversal of any changes...
const size_t n = ...;
p += n;
...
p -= n; // Restore earlier value...
free(p);
C++ smart pointers
In C++, it's best practice to use smart pointer objects to store and manage the pointers, automatically deallocating them when the smart pointers' destructors run. Since C++11 the Standard Library provides two, unique_ptr for when there's a single owner for an allocated object...
{
std::unique_ptr<T> p{new T(42, "meaning")};
call_a_function(p);
// The function above might throw, so delete here is unreliable, but...
} // p's destructor's guaranteed to run "here", calling delete
...and shared_ptr for share ownership (using reference counting)...
{
auto p = std::make_shared<T>(3.14, "pi");
number_storage1.may_add(p); // Might copy p into its container
number_storage2.may_add(p); // Might copy p into its container } // p's destructor will only delete the T if neither may_add copied it
Null pointers
In C, NULL and 0 - and additionally in C++ nullptr - can be used to indicate that a pointer doesn't currently hold the memory address of a variable, and shouldn't be dereferenced or used in pointer arithmetic. For example:
const char* p_filename = NULL; // Or "= 0", or "= nullptr" in C++
int c;
while ((c = getopt(argc, argv, "f:")) != -1)
switch (c) {
case f: p_filename = optarg; break;
}
if (p_filename) // Only NULL converts to false
... // Only get here if -f flag specified
In C and C++, just as inbuilt numeric types don't necessarily default to 0, nor bools to false, pointers are not always set to NULL. All these are set to 0/false/NULL when they're static variables or (C++ only) direct or indirect member variables of static objects or their bases, or undergo zero initialisation (e.g. new T(); and new T(x, y, z); perform zero-initialisation on T's members including pointers, whereas new T; does not).
Further, when you assign 0, NULL and nullptr to a pointer the bits in the pointer are not necessarily all reset: the pointer may not contain "0" at the hardware level, or refer to address 0 in your virtual address space. The compiler is allowed to store something else there if it has reason to, but whatever it does - if you come along and compare the pointer to 0, NULL, nullptr or another pointer that was assigned any of those, the comparison must work as expected. So, below the source code at the compiler level, "NULL" is potentially a bit "magical" in the C and C++ languages...
More about memory addresses, and why you probably don't need to know
More strictly, initialised pointers store a bit-pattern identifying either NULL or a (often virtual) memory address.
The simple case is where this is a numeric offset into the process's entire virtual address space; in more complex cases the pointer may be relative to some specific memory area, which the CPU may select based on CPU "segment" registers or some manner of segment id encoded in the bit-pattern, and/or looking in different places depending on the machine code instructions using the address.
For example, an int* properly initialised to point to an int variable might - after casting to a float* - access memory in "GPU" memory quite distinct from the memory where the int variable is, then once cast to and used as a function pointer it might point into further distinct memory holding machine opcodes for the program (with the numeric value of the int* effectively a random, invalid pointer within these other memory regions).
3GL programming languages like C and C++ tend to hide this complexity, such that:
If the compiler gives you a pointer to a variable or function, you can dereference it freely (as long as the variable's not destructed/deallocated meanwhile) and it's the compiler's problem whether e.g. a particular CPU segment register needs to be restored beforehand, or a distinct machine code instruction used
If you get a pointer to an element in an array, you can use pointer arithmetic to move anywhere else in the array, or even to form an address one-past-the-end of the array that's legal to compare with other pointers to elements in the array (or that have similarly been moved by pointer arithmetic to the same one-past-the-end value); again in C and C++, it's up to the compiler to ensure this "just works"
Specific OS functions, e.g. shared memory mapping, may give you pointers, and they'll "just work" within the range of addresses that makes sense for them
Attempts to move legal pointers beyond these boundaries, or to cast arbitrary numbers to pointers, or use pointers cast to unrelated types, typically have undefined behaviour, so should be avoided in higher level libraries and applications, but code for OSes, device drivers, etc. may need to rely on behaviour left undefined by the C or C++ Standard, that is nevertheless well defined by their specific implementation or hardware.
Dereferencing a pointer means getting the value that is stored in the memory location pointed by the pointer. The operator * is used to do this, and is called the dereferencing operator.
int a = 10;
int* ptr = &a;
printf("%d", *ptr); // With *ptr I'm dereferencing the pointer.
// Which means, I am asking the value pointed at by the pointer.
// ptr is pointing to the location in memory of the variable a.
// In a's location, we have 10. So, dereferencing gives this value.
// Since we have indirect control over a's location, we can modify its content using the pointer. This is an indirect way to access a.
*ptr = 20; // Now a's content is no longer 10, and has been modified to 20.
In simple words, dereferencing means accessing the value from a certain memory location against which that pointer is pointing.
A pointer is a "reference" to a value.. much like a library call number is a reference to a book. "Dereferencing" the call number is physically going through and retrieving that book.
int a=4 ;
int *pA = &a ;
printf( "The REFERENCE/call number for the variable `a` is %p\n", pA ) ;
// The * causes pA to DEREFERENCE... `a` via "callnumber" `pA`.
printf( "%d\n", *pA ) ; // prints 4..
If the book isn't there, the librarian starts shouting, shuts the library down, and a couple of people are set to investigate the cause of a person going to find a book that isn't there.
Code and explanation from Pointer Basics:
The dereference operation starts at
the pointer and follows its arrow over
to access its pointee. The goal may be
to look at the pointee state or to
change the pointee state. The
dereference operation on a pointer
only works if the pointer has a
pointee -- the pointee must be
allocated and the pointer must be set
to point to it. The most common error
in pointer code is forgetting to set
up the pointee. The most common
runtime crash because of that error in
the code is a failed dereference
operation. In Java the incorrect
dereference will be flagged politely
by the runtime system. In compiled
languages such as C, C++, and Pascal,
the incorrect dereference will
sometimes crash, and other times
corrupt memory in some subtle, random
way. Pointer bugs in compiled
languages can be difficult to track
down for this reason.
void main() {
int* x; // Allocate the pointer x
x = malloc(sizeof(int)); // Allocate an int pointee,
// and set x to point to it
*x = 42; // Dereference x to store 42 in its pointee
}
I think all the previous answers are wrong, as they
state that dereferencing means accessing the actual value.
Wikipedia gives the correct definition instead:
https://en.wikipedia.org/wiki/Dereference_operator
It operates on a pointer variable, and returns an l-value equivalent to the value at the pointer address. This is called "dereferencing" the pointer.
That said, we can dereference the pointer without ever
accessing the value it points to. For example:
char *p = NULL;
*p;
We dereferenced the NULL pointer without accessing its
value. Or we could do:
p1 = &(*p);
sz = sizeof(*p);
Again, dereferencing, but never accessing the value. Such code will NOT crash:
The crash happens when you actually access the data by an
invalid pointer. However, unfortunately, according the the
standard, dereferencing an invalid pointer is an undefined
behaviour (with a few exceptions), even if you don't try to
touch the actual data.
So in short: dereferencing the pointer means applying the
dereference operator to it. That operator just returns an
l-value for your future use.

basic c++ pointer question

if I have a function like that:
void doSomething(int& aVar)
{
// do something
}
and I have this:
int *aVar = new int;
*aVar = 10;
doSomething(*aVar);
Why should I call *aVar? isn't aVar already an address?
No, a reference is not a pointer. References are guaranteed to not be null; you cannot say the same for a pointer. When you pass an int to a function that expects an int& the reference will be taken automatically.
P.S. Don't think of it as an address or a fancy pointer. It is a reference, or an alias to an existing object.
doSomething(int&)
wants a reference not a pointer. The way to set up that reference as a parameter is to pass in an Int. Which is why
doSomething(*aVar)
works. If you want to use a pointer in the function say
doSomething(int*)
references and pointers are not the same thing (although they have a lot in common)
The asterisk, besides multiplication has two meanings:
a) When declaring a variable: *x means "X is a pointer"
b) When using a variable: *x (when x is of pointer type) means "take whatever is pointed by x" - the opposite of &x, which means "take the address of x".
The code:
doSomething(*aVar)
just wants to dereference the pointer "aVar" (take the value of type int pointed by it) and pass this value of type int as a parameter to the function.
The variable "aVar" stores an address of some integer value, not the value itself, so you have to use the "*" operator to dereference it every time you want to access the integer, not the memory address itself.
References in C++ are quite counter-intuitive ("disguised pointers"), so if doSomething takes a reference to int, you have to call it as if you were passing an actual int value, not a pointer. Hence you need the dereference operator.
A pointer is pointing to a specific memory address and a pointer has it's own data (ie the memory address it's pointing to). When you pass aVar to the function without dereferencing (the * operator) the pointer you would be passing the memory location of the pointer, not the memory location the pointer is pointing to.