Are HANDLEs as used by Win32 an example of what you are talking about? They may be implemented as a pointer to something, but that's not how you use it.
The nice thing about a HANDLE is they can be a pointer to kernel space, a pointer to something in user space, or an opaque index into an internal table of managed resources. If it was a pure pointer, then 0 has to be avoided as it can be mistaken for "no value" by users. Of course, you replace that with knowing to check for INVALID_HANDLE_VALUE.
IMO, HANDLEs are probably a bit too opaque for my taste, as you have to know what operations you should be using with them. I'd prefer opaque structs if I had to choose.
That is not, in fact, a nice thing. It is exactly what you would better have different types for, that implicitly do the right thing, and only ever do the right thing.
An opaque struct confers the ability to know the set of valid operations involving said type, while not giving up any advantages of a HANDLE. Issues of indeterminate size can be worked around with a single void*/uintptr_t field.
You are not wrong; the problem is, "different types" are language-specific, whereas HANDLE is a primitive (machine-level) type that is not and thus can be easily used from any language.