Main navigation | Main content
In today's lab we'll continue doing examples of progamming with C and debugging C programs, and see some examples relating to numbers in binary. As a reminder, lab grades are solely attendance based, so if you are here, work on the lab and then get checked off by a TA, you are fine grade-wise. But if you don't finish the lab activities during the lab period, please consider coming back and working on them later to get more practice. If you have questions about materials from the labs after class, ask them on the Piazza forum or in office hours (information about both of these are on the course web site).
[This question is repeated from last week, but we'd recommend working on it today if you haven't already gotten to it.]
The Fibonacci sequence is a famous series of integers with a very simple construction. The first two numbers are 0 and 1, and every number thereafter is the sum of the previous two numbers, e.g. the third and forth numbers are (0 + 1) = 1 and (1 + 1) = 2. Your friend is writing a Fibonacci generator as their very first C program, but they've made an absolute mess of it! Help them fix their obvious compilation errors and the runtime errors that lurk beneath.
Get a copy of their program with:
cp /web/classes/Spring-2020/csci2021/labs/0x2/lab1-fibonacci.c .
printf
and scanf
)
For this question you are going to complete a program that
requires some scanf
and printf
statements. We will also ask you to write a bit of code
regarding binary representations. To get the code
template:
cp /web/classes/Spring-2020/csci2021/labs/0x2/binary_template.c .
You will be printing and scanning in values other than %d in
this case. In fact, you will need to print and scan for hexadecimal
and octal representations of integers. Every place a
scanf
or printf
is needed will be
marked on the template. It is your choice as to the messages you give
with your printf
statements.
Once you get all the printf
and scanf
statements complete, run the program to see if you know your
hexadecimal and octal representations well enough. (Note: for input of
your guesses, you DO NOT need to use the prefixes, i.e. ‘0x’
for hexadecimal and ‘0’ for octal.)
Something you might have noticed is that we did not
ask for a binary representation. This is because printf
and scanf
do not have a specifier for binary. In this
case, write some code that will print the binary representation of an
integer. A more in-depth description is given in the template.
For question 3, you will be debugging the Fibonacci program from last week that has had a bunch of mallocs added. This is to help you see some of the mistakes you may later find you've made yourself when trying to use malloc. To get the file:
cp /web/classes/Spring-2020/csci2021/labs/0x2/fibMalloc_buggy.c .
The program does not compile or run as it should as the mallocs, frees, etc. are not all used correctly. It is your job to fix them so that the program runs smoothly.
First, we ask that you get the file to compile. Make sure you add the flags -Wall and -g when doing so. This will allow you to use gdb and valgrind in the next step as well as give all possible warnings when compiling. Both of which will help you.
After the program compiles, try running it. You should see that it is not doing what it should and may even seg fault. You could just stare at the code but using gdb and valgrind will help you find the problems a bit easier. First, for valgrind, run the following line in the terminal:
valgrind ./executable
This should run your program under valgrind which looks at your program’s memory usage. Look to see what kind of messages are brought up, what information it gives, etc. Some basics are error messages, memory used, and the number of frees and mallocs. Based on this, you should be able to fix all the issues.
As a warning, there may be a message of an invalid free error. This could be due to multiple frees or freeing invalid memory. You can look at the rest of the message to possibly trace where this occurs.
A quick resource for using valgrind is this tutorial. There's also the official website.
If you want to try another way to debug a program, you can use gdb. Firstly, make sure you compiled your file with -g. This makes sure there are debugging flags on your program. Next, to run gdb use the command
gdb -tui ./executable
You can use gdb without the -tui, but -tui, the text user interface, allows you to look at the relevant code you are working on. You can look at both and see which you prefer.
Next, to run the program, type run
. You’ll see that the
screen gets a little messed up when you run certain commands. To fix
it, press Control-L.
To start the debugging, use this command:
start
This allows you to run the program and stop at main
.
The command start replaces setting a breakpoint at main and
using the run command. If you want to stop at other
functions, you can set a breakpoint with this command:
break function_name
NOTE: If you ever go into a library function, such as
printf, you an use the command finish
to get
out.
After the program has stopped, to keep going, you can either say
continue and run the rest of the program, or next
and it will move one line in your code. Once you get past the
initializations, or to the printf
, type the command:
print i
You should see that it showed you the value of i without
having to add a printf
in your program. Whenever you
are done with gdb, just use q or quit to
exit.
Now that you know the basics, a helpful guide to gdb is this tutorial. The complete manual can help you with finding other commands you can use in gdb to help you debug.
[This question is repeated from last week]
You might have already heard of the Mandelbrot set, a well known fractal that has a simple definition in terms of an iterative operation on complex numbers. For the purposes of this problem it's just a pretty picture, but in order to draw that picture you need to complete a program by implementing the operation of multiplication over complex numbers. We'll represent a complex number as an array of two doubles, the first (index 0) for the real part and the second (index 1) for the imaginary part. Copy the framework code with:
cp /web/classes/Spring-2020/csci2021/labs/0x2/lab1-mandelbrot.c .
And then complete the program filling in the implementation of the function complex_multiply. Your function should read from the arrays a and b, and write the result of the multiplication to c. If you're not familiar with complex multiplication you can find the definition in the usual kinds of online places.
You can test your program by running commands like:
./lab1-mandelbrot 900 600 >mandelbrot.pgm
eog mandelbrot.pgm
Where eog is an image-viewing program. Your result should look like a more detailed version of this: