a – argument b – char (byte-wide integer) c – char (if it's really a character) d – double (64-bit floating-point number) e – enum f – float (32-bit floating-point number) g – global h – has-a (instance variable or struct element, i.e., this thing has a whatever) i – int (32-bit integer) j – k – const l – long (64-bit integer) m – macro (replaces the ALL_CAPS_CONVENTION) n – number of (i.e., how many) o – object (usually followed by a class name) p – pointer q – r – reference (C++ not-quite-a-pointer) s – struct (usually followed by the conceptual name of the struct) t – typedef (usually followed by the conceptual name of the type) u – union (usually followed by the conceptual name of the union) v – vector (array) w – word (16-bit integer, this was the wordsize on the CPUs K&R used) x – executable (used for labels and function pointers) y – yes-or-no (i.e., boolean) z – size
There is unfortunately no nice way of differentiating signed and unsigned integers in this scheme.
There is unfortunately no nice letter remaining to denote static. If you eschew globals, as many people do, you might consider using g for static, as is done in Java.
The n prefix is easily overused, and is often confused with the z prefix.
The order of prefix elements works like this, where underscore indicates nothing:  [agh_][k_][prsuv_][bcdefilnowxyz]
The first group indicates where the variable came from. Is it an argument (a), a global/static variable (g), an instance variable (h), or a local variable (no prefix)?
The second group indicates whether you can change the variable's value. Is it a constant (k), or not (no prefix)?
The third group indicates the reference type. Is it a pointer (p), a reference (r), a struct (s), a union (u), an array (v), or a simple value (no prefix). These can be stacked together, as in ppvs: a pointer to a pointer to an array of structs. When describing a multi-dimensional array, use one v for each dimension.
The fourth group indicates the variable's type, where most of the prefixes are highly mnemonic. The n and z prefixes are assumed to indicate int values. If you need them to be something else, prefix them with their physical types, e.g. bn or lz.
When you use the e, o, r, s, or u prefixes, you will usually append the relevant conceptual name as the first word of the suffix, as in eColor, oDate, or sPoint.
Typedefs are indicated by a leading t prefix. The most common examples are te, ts, and tu. as in teColor or tsPerson.
In practice, it is sometimes advantageous to go outside the prefix-ordering rules shown above. Do so if it makes sense, but try to have some empathy for a reader who is not you.
Don't worry if some of your prefixes become quite long. The alternative is worse.