Difference between revisions of "Testing and debugging"

From Tux
Jump to: navigation, search
(Logic errors)
(Debugging)
Line 25: Line 25:
 
int fcn(int x)
 
int fcn(int x)
 
{
 
{
         return (x + 5);
+
         return x + 5;
 
}
 
}
  
Line 32: Line 32:
 
         int y = fcn("Hi");    // Error: function expects an int
 
         int y = fcn("Hi");    // Error: function expects an int
  
         return(0);
+
         return 0;
 
}
 
}
 
</source>
 
</source>
Line 45: Line 45:
 
         cout << pow(3.0, 2.0) << endl;  // Error: did not #include <cmath> and did not have using namespace std;
 
         cout << pow(3.0, 2.0) << endl;  // Error: did not #include <cmath> and did not have using namespace std;
  
         return(0);
+
         return 0;
 
}
 
}
 
</source>
 
</source>

Revision as of 16:47, 13 January 2018

Testing and debugging are two critical components involved in writing computer programs.

Debugging refers to the process of fixing errors in a program after it has been written. The two primary types of errors are:

  • Syntax errors that prevent the program from compiling
  • Logic errors that do not prevent compiling, but cause erroneous or unexpected output

Testing refers to the process by which a program is determined to be functioning properly and free from logic errors.

Debugging

Syntax errors

Syntax errors are typically the easiest to fix. Common instances of syntax errors would be:

  • Forgetting a semicolon at the end of a statement or a typo.
cout << "Hello!" << endl     // Error: no semicolon at the end
cout << "Welcome." << end;   // Error: should be endl instead of end
  • Passing a value of one type to a function that expects a value of another type.
int fcn(int x)
{
        return x + 5;
}

int main()
{
        int y = fcn("Hi");    // Error: function expects an int

        return 0;
}
  • Not including the appropriate header file when using an object or function from it.
#include <iostream>

int main()
{
        cout << pow(3.0, 2.0) << endl;  // Error: did not #include <cmath> and did not have using namespace std;

        return 0;
}

Syntax debugging

When a program will not compile because of syntax errors, the compiler typically does a good job of telling you exactly what line and column the error occurred in as well as the specific type of error. Note that if there are multiple syntax errors, the compiler may only catch some of them. As errors are fixed and the user attempts to compile again, the additional errors will be caught by the compiler and these must also be fixed.

See below for some compiler messages and how to interpret them:

#include <iostream>

using namespace std;

int main()
{
        cout << "Hello!" << endl
        cout << "Welcome." << end;
}

Compiler messages:
test.cpp: In function int main():
test.cpp:8:2: error: expected ; before cout
  cout << "Welcome." << end;
  ^

Note that even though there are two errors, only the first is caught. To fix this error the semicolon needs to be placed before the code in line 8. Really where it should go is at the end of line 7. Upon fixing this error and compiling again, the following error occurs:

test.cpp: In function int main():
test.cpp:8:24: error: end was not declared in this scope
  cout << "Welcome." << end;
                        ^

Again, the compiler notices there is no such thing as end and points it out. Either there should be an identifier (i.e. a variable) called end or the programmer mistyped and meant endl. Upon fixing this error the program will compile.

Getting experience with syntax error messages from the compiler and fixing them is essential for a programmer.

Logic errors

Logic errors are typically the hardest to fix. Common logic errors arise from:

  • Loops being off by one
  • Using = instead of ==, or vice versa
  • Attempting to modify an element of an array or dereferenced pointer that is out of bounds -- this type of error usually results in a segmentation fault
  • Deep/infinite recursion, leading to a stack overflow which may or may not manifest itself as a segmentation fault

Two common ways of fixing logic errors are:

  • Adding output (e.g. cout) statements throughout the code to display where the code is currently executing and/or what the values of variables are
  • Using a debugger such as gdb

Testing