A variable in a C/C++ program can be conveniently viewed as an appropriate "data container" of a definite size. In this (and the previous) chapter we have discussed this container as a segment of memory. The address of the segment (i.e., the address of its first byte) is referred to as the address of the variable and the length of the segment as the size of the variable. The symbolic references to the variable in the source program are replaced by the compiler with the address references to that segment. The data type of the "container" determines which binary code is used to store the value or to interpret the value stored there.
Pointers are special values and variables with two attributes - the first is an address, the other is a data type. Thus a pointer determines which location in the memory we are referencing as well as how to interpret the binary code at that location. In essence, looking through the pointer's eyes, we can see where it points to a "virtual object" of the appropriate data type. Thus, pointers allow us to interpret the contents of a memory segment in various ways and to reference such virtual objects without using their names or even giving them names . This gives C/C++ programs a lot of flexibility and problem-solving power, but on the other hand it can be dangerous (since dangling or incorrectly set pointers cause memory access faults) and in general prevents C/C++ programs from being portable or interpretable in a Java-like platform-free manner.
Explicit dynamic memory allocation and deallocation goes hand in hand with pointers, putting the onus for memory handling on the programmer. This has both positive and negative consequences: memory handling can thus be made predictable and highly efficient, but it can also end up being unpredictable, inefficient, or (even worse ) outright incorrect. The infamous "memory leaks" are result of such improper handling of memory allocation and deallocation: not all the allocated (but no longer needed) memory is deallocated and hence, as the program executes, the unused yet allocated memory keeps accumulating to the point of becoming detrimental to the running program, other running programs, or even the operating system. Thus, in a general setting, C/C++ cannot have a garbage collector - unless you are willing to refrain from a free-format explicit memory allocation in favor of a restricted allocation handled through mechanisms with which your custom-made garbage collector can work.