The Hungarian naming convention---for which Hungarians should not be held accountable---represents an unfortunate attempt to set some conventions for coding. What is really obtained by such naming conventions is total breakdown of abstraction barriers. One of the fundamental principles of software engineering is to hide from a client all information that does not concern that client. Prefixing a variable by its type exposes exactly these unimportant implementation details to client code. Now, if the type of the implementation of a data type changes, all of the names of instances of that type must be altered as well.
One might wonder, then, why this practice is so common. The reason is that early versions of the Unix C compiler had a particularly stupid way of managing its symbol table, requiring all field names of all structures to be unique. The only solution to the programmer was to use some kind of prefixing convention to avoid clashes. Modern compilers (and indeed it is required by the ANSI/ISO standard) have a separate namespace for each structure so that field names now have to be unique only within the same structure. There is therefore no need (and there hasn't been any need for a long time) to prefix field names by the structure name.
Notice that suffixing is less useful than prefixing, since some linkers limit the number of significant characters that they can handle. With such linkers, the names may very well be truncated after six characters or so, causing two names such as insert_set and insert_queue to clash.
For the same reason (limited number of significant characters in the linker) module prefixes must be fairly short, or else not enough characters will be left for the names of the interface routines themselves. For instance, two names such as tree_delete and tree_destroy might become indistinguishable. The solution is to invent a shorter prefix of (say) three characters at most. Problems like this might disappear entirely in the future. The reason for the existence of such problems today, is that we still use linker technology from the 1960s. There is no reason (other than backward compatibility) for modern linkers to have such limitations.
For names that are locally known to a module, there is no need to use a prefix. Indeed, it could be useful for different modules to use the same name for internal functions with a similar purpose. For instance, the name init, may be used inside a module to initialize it.
Similarly, the variable name i and j are always loop counters. Never use these variable for other purposes, and always use these variables first for loop counters.
It is important never to mislead the maintainer by using incorrect names. An example of bad practice is the use of the identifier fd (usually a general-purpose file descriptor) for an object of type FILE *. Now, a file descriptor is defined in Unix to be an integer that is returned by the operation open(), and used as an argument to operations such as read() and write(). Distinct from it, there is also the concept of a file pointer FILE *. This is the type return by fopen() and used in operations such as fprintf(), etc. But a file pointer is not a file descriptor. Therefore, using fd as a variable of type FILE * is highly misleading to the maintainer.
Similarly, it is sometimes reasonable to call variables x or y. For instance, as arguments to a graphics routine that uses them to determine the position on the screen for some kind of object, these humble variables are well named. Similarly, for a function that implements arbitrary precision multiplication of two numbers, there is no reason to call the arguments multiplicand and multiplier. Simply use x and y!
Short names can also be used where the visibility of the variable is very limited. For instance, in order to traverse a list using a temporary pointer variable, we might use the name p for this variable as in the following example:
{ list p; for(p = first; p; p = p -> next) { /* only a few lines */ } }Using a longer name may cause the line
for(p = first; p; p = p -> next)to require more than 70 or so characters, making it hard to read. We may then have to split it into several lines, which increases the code size, i.e., the source, and creates a less common way of indenting the for loop.