You are right about the & providing a pointer to the starting address. In fact, the standard says:
When a pointer to an object is converted to a pointer to a character
type, the result points to the lowest addressed byte of the object.
Successive increments of the result, up to the size of the object, yield
pointers to the remaining bytes of the object.
Which is clear enough, except it doesn't state the endianness. So the lowest addressed byte may carry higher order or lower order significant bits. The language doesn't say anything about that.
The C standard says this about bytes:
A byte is composed of a contiguous sequence of bits, the number of
which is implementation-defined. The least significant bit is called
the low-order bit; the most significant bit is called the high-order bit.
It also says that size of a char must be 1 byte and that a byte must be at least 8 bits. Other than bit fields, it also says that all objects must be an integral number of bytes in size. But again, a byte can be more than 8 bits. On the PDP-10, which is a 36-bit word machine using 18-bit addressing (I think), a C implementation would probably use 9-bit char/bytes. But 12, 18, and 36-bit chars would also meet the standard.
Assuming you don't want to trust limits.h and assuming that there aren't any padding bits, you can write some code to verify the number of bits in a byte:
int bits( void ) {
unsigned int count;
unsigned char c= -1;
for ( count= 0; c != 0; ++count ) c &= c - 1;
return count;
}
(Yes, I assign a signed number to an unsigned char, a conversion for which the standard clearly defines in detail.)
However, an implementation may actually use padding bits. For example, the above PDP-10 may specify that an unsigned char occupies 9 bits in memory (four per word) but may also specify that the "value bits" are 8 and the "padding bits" are 1. So you actually may not be able to access the padding bits to find out their existence without doing non-standard tricks. (They won't be mentioned in limits.h and you can't write standard C code to find out about them, either.)
The addresses of variables are not separately stored in other variables, unless you specifically set up new variables for that purpose. "Seeing" an address means computing it. Since every object in C must be an integral number of bytes in size and since the pointer formed by using & must give you the lowest address value of the object, it follows that each successive byte will be at an address exactly 1 higher than the prior one. You can use sizeof() to determine how many. Padding bits, though, you cannot ever see. (Alignment bytes used to pad out objects in structures or between structures you may be able to, though.)
You can always cast a pointer to an object with sizeof() larger than 1 to a char * pointer and access successive bytes. But in general, because of allowed endian differences and because of the possibility of padding bits permitted by the standard, you can't know how to interpret what you see if you do that or even if you will get every bit in the process. For example, in the 36-bit case where a char is 8 value bits plus 1 pad bit and sizeof(int)=4, you could convert the int * pointer to a char * and access four successive 8-bit values and find that you've only got 32 bits, not 36 bits. So you wouldn't even be able to get all 36-bits of the valid int that way.
The point here is that while things usually work in ways you would naturally guess they would, there exist machines and compilers where such assumptions would get you into trouble. Most of the examples you were given here make assumptions that would not be true on a PDP-10, for example. Just be aware. But have fun, too!