Overview, Arrays, Errors, Debugging
First, let's have a quick overview of some C basics which you've seen. Here's a chart of rough equivalences:
Scheme | C |
---|---|
(define x 3) | int x = 3; |
(set! x 3) | x = 3; |
(if (= x y) #f #t) | if (x == y) {false;} else {true;} |
(define foo (lambda (x) (+ x x))) | int foo(int x) {return x+x;} |
(set! x (read)) | cin >> x; |
(printf "~s~ x) | cout << x; |
What does the following program do?
#include <iostream.h> int main() { int i; int n; int x = 0; cin >> n; for (i=0; i<n; i=i+1) { x = x + i*n; } cout << x; return 0; /* 0 indicates no error, to UNIX */ }
Write a program that reads two integers as input and prints the sum of all the numbers between (inclusive) them. First try this assuming the first input is less than or equal to the second input. Next, allow the second input to be less than the first.
Here's some more Scheme/C rough equivalences:
Scheme | C |
---|---|
(define v (vector 1 2 3 4)) | int v[4] = {1,2,3,4}; |
(vector-ref v 2) | v[2]; |
(vector-set! v 2 5) | v[2]=5; |
The following code fragment illustrates how to pass an array to a C function. Note that the main trouble is that the called function doesn't have an automatic way to know how big the array is. I.e., there is no direct equivalent of Scheme's vector-length. One solution is to also pass the size the function.
bool func(int v[],int vsize) { ... } int main() { ... int v[10]; ... func(v,10); ... }
Write a function that takes an array of integers and an integer indicating the array's size. Return a boolean indicating whether the array is sorted, i.e., if each element is bigger than the previous one.
As in DrScheme, you can encounter errors at two times:
We already saw some compile-time errors in the first C lab, but here are some more examples.
Copy the program /home/comp210/public_html/Labs/lab13/error1.cc into your directory and compile it. It complains
error1.cc: In function `float c2f(float)': error1.cc:6: parse error before `}'A number just after the file name indicates the line number in the file where this error occurs. I.e., in the function c2f, there is a syntax error just before the closing brace on line 6. Look at the file -- can you fix the problem?
Any time it complains about a "parse error", that means you've left something out that is necessary (like a comma or semicolon or keyword), put something extra in, or mistyped something (like misspelling a keyword).
All of the previous errors have been found during compilation. Give what we have seen of C/C++ so far, it's pretty hard to have a run-time error, assuming you follow your program templates. (This ignores the possibility that your program may compute something correctly, just not the right thing.)
Probably the easiest way to get a run-time error so far is to misuse arrays. The most important thing is to always index an array with a value in the range from zero to its declared size minus one. Otherwise, C will quietly allow a bad indexing, and strange things can happen. Look at, compile, and run /home/comp210/public_html/Labs/lab13/badarray.cc.
Let's look at some possible run-time errors not using arrays. Look at and compile /home/comp210/public_html/Labs/lab13/sum.cc. This will sum the squares of all integers in an interval (like you should have written earlier in this lab). Run the compiled program:
% sum 1 3 14As expected, 1*1 + 2*2 = 3*3 = 1+4+9 = 14.
% sum 10 1000 333833215We'll take the program's word for it -- it's right.
% sum 10 10000 -1624114373Huh?!? What happened is overflow. The result is too big to be an int. Change the program to use floats and try it. Can you figure out about how big an int can be? Can you figure out about how big a float can be? For more details, see last week's optional lab on arithmetic precision.
Look at and compile /home/comp210/public_html/Labs/lab13/ack.cc. This is a funky function called Ackerman's function. The result of this can easily be a really big number, so we use floats instead of ints. Run the compiled program:
% ack 3 2 4We can hand-evaluate this to see that ack(3,2) = ack(2,ack(3,1)) = ack(2,2) = ack(1,ack(2,1)) = ack(1,2) = ack(0,ack(1,1)) = ack(0,2) = 2*2 = 4.
% ack 3 3 65535Ok, we'll take the program's word for it -- it's right. I told you the results get big quick.
% ack 3 4 Segmentation faultHuh?!? This error means that something really bad happened and the computer got VERY confused. Basically, we made more recursive function calls than C/C++ would allow us. To get a more complete answer, take Comp320. Scheme doesn't have this same limitation (cf. Comp311), but it's rare to run into this problem.
Debugging a C program can be more difficult that debugging a Scheme program because we don't have the equivalent of Donkey to step through our programs. In this part of the lab, we will find and fix some program errors. These will be examples of some of the common C programming mistakes. We also demonstrate a common technique for debugging.
What does this program in /home/comp210/public_html/Labs/lab13/debug1.cc do? Can you fix it so it does the intended calculation? Edit, compile, and run it until it does what you expect.
For small programs like this, it's often not too difficult to step through the evaluation either in your head or on paper. But errors can be hard to find, especially when you "know" that your program is "obviously" right. One technique for effectively stepping through the interesting bits of the computation is to print some interesting values while your program is running. We saw this before for Scheme also.
Copy, compile, and run /home/comp210/public_html/Labs/lab13/debug1print.cc, which is like the previous program, except that we print out some values along the way. Observe that, for readability, we label what we print, so that we don't confuse ourselves with all of this output.
Did you find the uninitialized accumulator and the incorrectly ordered side-effects?
Good places to print out values include
There are ways to extend this technique, e.g., having multiple "levels" of debugging which print out different amounts of information. Also, there really are some tools that help you step through C programs (e.g., gdb, adb). With practice, these can be very helpful, but they aren't as easy to use as Donkey.