Passing by address and by reference are two different concepts.
Code:
void foo(T* p); // This is pass by address/pointer
void foo(T& p); // This is pass by reference
When you pass by address, a copy of the address is made and copied into the pointer argument in the function. This is a given. That is how the standard mandates it.
References are different, however. The standard states that they are aliases.
So
Code:
void foo(int& n)
{
// n is now an alias of main_n. That is, they are the same variable, but with different names.
// n is a different name, another alias, if you will, of main_n in main.
}
int main()
{
int main_n = 0;
foo(main_n);
}
In practice, many compilers implement references using pointers, but those are details we do not need to concern ourselves with. What the standard says is enough.