At key points in well-organized programs you can make assertions, such as "the index points to the next open array element." You should test these assertions during development with the ANSI C assert macro, and document them for the maintenance programmer (who is often yourself). You could represent the assertion above, for example, as
#include <assert.h> . . . assert(nitems < MAXITEMS && i == nitems); . . .If the condition holds, all is well and execution continues. Otherwise, assert prints a message containing the condition, the file name, and line number, and then calls abort to exit the program.Use assert to validate the internal logic of your program. If a certain thread of execution is clearly impossible, say so with a call assert (0):
switch (color) { case RED: . . . case BLUE: . . . case GREEN: . . . default: assert (0); }Every function essentially has a contract with its users to "give me input that satisfies certain conditions and I'll give you this output." You can enforce the contract by validating parameters with assert. A function that takes a string argument, for example, should make sure the string really exists:
char *f(char *s) { assert(s); . . .Assertions are for programmer errors, of course, not for end-user errors. Nothing a user does should create a NULL pointer; that's clearly your fault, so it is appropriate to use assert in such cases. My custom is to use asserts generously throughout my code and then replace assertions that might be affected by the user with more bulletproof exception handling. Any remaining assertions should not be needed in released code (because it's debugged, right?), so I define the macro NDEBUG to disable them. You can either include the statement
#define NDEBUGin the beginning of the code, or define the macro on the command line if your compiler allows it. (Most support the -D option for this purpose.) With NDEBUG defined, all assertions expand to a null macro, but the text remains in the code for documentation.