a pointer's type
Every pointer carries a label saying what kind of thing it points at: int * means 'address of an int', char * means 'address of a char', double * means 'address of a double'. The address inside might be the same number, but the type tells the compiler how many bytes to read there and how to interpret them.
The pointee type does two real jobs. First, dereferencing: *p on an int * reads 4 bytes and treats them as an int, while *p on a char * reads exactly 1 byte and treats it as a character. Second, pointer arithmetic: p + 1 advances by the size of the pointee, not by one byte — so on an int * it jumps 4 bytes forward, landing on the next int. The type is what makes p[i] mean 'the i-th element' regardless of element size. Pointers of different types are generally NOT interchangeable, and the compiler will warn if you assign one to another without a cast.
Two pointer types stand apart. void * is the typeless pointer: it holds an address but has no pointee type, so you cannot dereference it or do arithmetic on it until you convert it to a concrete type. And the pointee type may itself be const or otherwise qualified — const char * promises 'I will not write through this pointer' — which is the basis of const-correctness.
Given char *c = (char*)0x1000; and int *n = (int*)0x1000; both hold 0x1000, but c + 1 is 0x1001 (one byte on) while n + 1 is 0x1004 (one int, four bytes, on). Same address, different stride.
The type, not the address, decides the step size and how many bytes *p reads.
All object pointers are the same width in memory (typically 8 bytes on a 64-bit machine) — the type is compile-time information, not extra storage. Casting an int * to a char * does not change the address, only how the compiler reads and steps through it.