A) As part of type declaration:
Example: int* p;
The * in this context means that p is a pointer variable of type int. The values it can hold are addresses of int variables. Not addresses of char, of float, of double or anything else, only addresses of int. And it can't hold int values, that's the job of plain int variables.
Example: int& p;
The & in this context means that p is an alias for another variable. We have chosen to give some other variable a second name, the name p. That's all.
B) Elsewhere:
Example: cout << *p;
The * in this context means "dereference p". p is a pointer and as a pointer of a certain type it stores an address of a variable of that type. Here we are telling it, don't give us the address. Give us the value next to that address. In other words, the value held by the variable the address of which the p pointer was pointing to.
Example: cout << &p;
The & in this context means the opposite of the previous example. Here, p is a variable of a certain type and we are not telling it to give us its value, but its address.
The moral of the story is that each variable in programming is associated with two numbers: 1) its address or location in memory; 2) the value that it holds.
Want a variable to hold memory locations of specific types? Declare it a pointer with a *.
Want a variable to have an alias? Declare the alias with an &.
Want a pointer to display, not its address but the value of the variable that it points to? Dereference it with an *.
Want to find out the address of a plain old variable? Use the & operator so that you don't get its value.