Passing by address and by reference are two different concepts.
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.
void foo(T* p); // This is pass by address/pointer
void foo(T& p); // This is pass by reference
References are different, however. The standard states that they are aliases.
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.
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_n = 0;