If you keep track of which boxes are and are not runtime memory cells, that should be enough to work out any particular C pointer problem except the pointer-array almost-equivalence mess.
When it comes to understanding memory in C, another important aspect is understanding how linkers and loaders work. Also, it's good to know something about calling conventions.
Also, when you get to manually allocated heap data (which this article doesn't cover) you don't have to worry about deallocations... usually.
Variables? What state? Everything is puuuuuuuuure.
In Python:
Everything is an object (numbers, true/false values, strings, etc), some are mutable and some are not. Variables are temporary labels on objects (think of them as hard links).
In Rust/C++:
There are various types of boxes / smart pointers (shared, unique, heap, etc), and unsafe / raw pointers should be avoided when possible.
In C:
Not every variable has a data type, e.g. void or function pointers.
A void pointer has type "void* "; a function pointer also has some appropriate type.
Not every object has a type (e.g., a chunk of memory allocated by `malloc()`), but if "variable" means "object created by a declaration", then yes, every object has a type.