F-Forgotten
F.init
Many errors are caused by the programmer wanting the computer to "Do what I mean, not what I say." The most basic case of this is an instruction that is accidentally left out of the program. One of the most common types of instructions to leave out are ones that initialize variables. This is an F.init error.
Many variables are not initialized when they are defined, and many languages do not assign a default value in this case, which results in the variable containing whatever value happens to be in the memory location the variable is stored at. An uninitialized variable becomes a bug when it is actually used in code that expects it to be initialized. Usually, this error happens because certain paths through the code avoid the initialization, although in some cases, the variable is never initialized. The more unusual the uninitialized path is, the less likely such a bug will be found early. In code such as the following
int a;
if (somethingunusual()) {
// code that does not modify a
} else {
a = 12;
}
// code that expects a to be initialized
the error might go undetected for a while, depending on how often somethingunusual() is true.
A common case is the loop counter not being properly initialized:
int k;
while (k < max_tables) {
// some code: k was never initialized
}
Some languages make this impossible, depending on the type of loop command used, and the level of checking that the compiler or interpreter is asked to do.
It's also possible the initialization code is correct for the loop counter, but is missing for a different variable that is compared in some way against each of the values that are being looped through. Code such as the following
for (i = 0; i < 20; i++) {
if (array[i] > biggest)
biggest = array[i];
must ensure that biggest is initialized properly before the loop begins. For example, there might be some known value that would be smaller than any value in the array.
F.missing
Other statements besides initialization can be left out; the case of missing initialization is just so common that it deserves its own subcategory. F.missing is the general case.
Programmers can neglect to type in a statement, or accidentally delete it while moving code around, cleaning up comments, and so on. Finding these types of bugs can be tricky unless a comment makes it obvious:
//
// First read a, then tokenize it, then store it.
//
read(a);
// perhaps a call to tokenize(a) is missing here?
store(a);
Problems with loop counters can occur when the loop counter is improperly modified. For example, a loop might look like the following:
while buffer_index < 100:
# some code
if doublebyte:
buffer_index += 2
else if singlebyte:
buffer_index += 1
If doublebyte and singlebyte are both false, buffer_index won't be incremented and the code might get stuck in an infinite loop.
Keep in mind that loops can have more than one variable that is logically acting as a "loop counter," even if it doesn't appear in the statement that defines the loop. For example
pointer = first;
for (count = 0; count < maxcount; count++) {
// code
if (jumptonext)
continue;
// more code
pointer = pointer->next;
}
count and pointer are both logically functioning as loop variables. Because count is modified in the for() statement itself, it will always be updated for each iteration of the loop. But pointer is modified by code within the loop body, and it is possible that the code might iterate the loop without advancing it (such as in the previous example if the continue statement is executed).
F.location
The F.location refers to code that is in the wrong sequence within the program. One example is initializing a variable inside a loop rather than outside it:
while somecondition():
count = 0
# code that updates count
Another example of F.location is when the sequence of instructions does not match the intended order of operations. Often, two instructions are swapped. This code tries to zero out an array element after it has included it in the total, but has the statements in the incorrect order:
array[f] = 0;
total += array[f];
An arithmetic operation can also have swapped statements, such as these two attempting to compute the hypotenuse of a triangle:
result = Math.sqrt(c);
c = Math.pow(a,2) + Math.pow(b,2);
Instructions can be placed in the wrong block of code, particularly if blocks are nested several layers deep:
if (found_blank) {
if (string_done) {
clean_up();
if (buffer != NULL) {
free(buffer);
}
}
return;
}
In this case, it's likely that the return statement should be one layer deeper in the nesting (that is, the function returns only if string_done is true, not just because found_blank is true). Of course, the code could be correct as written. The point is that it is easy to miss such an error when looking at the code because the only difference is the order of the tokens in the code.
I'll also use F.location for cases where the code in question should not be present at all:
// sort the list
list_head = sort(list_head);
list_head = null; // what is this doing here?
display(list_head);
The extraneous statement might have been a remnant of a previous algorithm, a cut-and-paste error, or simply a programmer's mistake.
|