By dynamic analysis, we mean executing a program. This can be done by compiling into machine code and running the code, or by interpreting the program (either directly or by first converting into an intermediate form). By observing the behavior of the program, it is tempting to presume to know all about it. Dynamic analysis is an essential part of programming, since no programmer could claim his or her program to be complete unless it actually ran according to expectations.
A novice programmer can be beguiled into thinking that his job is accomplished because his chosen set of inputs leads to non-erratic behavior. Experience, however, tells us that whereas testing can show the presence of bugs, it can never demonstrate their absence. The number of combinations of inputs to even a relatively simple program can be astronomically high and in general it is completely impractical to test all combinations of input.
Static analysis on the other hand, is not confined to one set of inputs. If, for example, somewhere in the code, a signed quantity is compared with an unsigned quantity, the signed quantity gets promoted to unsigned! No harm arises until the signed quantity is actually negative. A static analysis will discover the problem without the programmer having to concoct a set of inputs that will deliver a negative to the proper site.
Or consider a construct that the C or C++ standard considers "implementation dependent" such as the order of evaluation of sub expressions in a larger expression or the order of initializations in a C++ program. By making many test runs while using the same compiler you will probably not discover any portion of your code that would be vulnerable to such dependencies. However, if you were to port your application to a new operating system, or obtain a new compiler, or simply change the optimization settings of your current compiler, the implementation dependent order assumptions can change and trigger a bug in what seemed to be solid code.
Static analysis has a different perspective than a compiler. Rather than finding a way that your program can be interpreted, it looks for ways in which your program might be misinterpreted.
Another commonly occurring class of Warning is the redundant element. If a particular function, for example, is not being called, then is the function truly redundant or should it have been called but, through some oversight, wasn't. Clearly, only the programmer can answer that question but it is a question that doesn't arise during dynamic analysis.
There's an interesting analogy with the health care profession. Dynamic testing is like emergency room care whereas static analysis is like preventative care, such as maintaining a healthy diet and exercise program. If your system crashes, the obvious tool to use is the dynamic test, i.e. a traditional debugger, just as the obvious place to take a person who has just been in an accident is the emergency room. However, just as good health practices faithfully followed can help to keep you out of the emergency room, so a conscientious use of static analysis can help to keep your program from failing. No analogy is perfect and the degree to which it is not, actually favors static analysis. If your system crashes, you might as well run the static analysis first because if the bug is found, the offending line will be explicitly indicated. But to convince yourself of this, you need to run a static analysis on your own code.
Thus, static analysis can be an extraordinarily effective complement to dynamic analysis.