You should have already completed the pre-lab.

Goals for this Lab

  • Get your system set up for work this quarter
  • Familiarize you with most of the tools necessary for all steps in the C development cycle: edit, compile, and execute. We will learn debugging later.
  • Write a simple C program to get used to the syntax.

For this lab, you are welcome to get technical help from another student on how to use or install any of the tools involved. You may also get syntax help on C. You may not, however, get help on the algorithmic portion of the exercise outside of office hours or piazza questions to TAs or instructors.

This lab is broken down into several steps:

Remember to turn in your completed lab1 questions when you first arrive

Set up

Make sure you filled out the Student Information Form

Your personal repository is
https://phoenixforge.cs.uchicago.edu/svn/CNET-cs152-win-17
with your own CNet ID in place of CNET.

To check out the repository to your current location:
$ svn checkout https://phoenixforge.cs.uchicago.edu/svn/CNET-cs152-win-17

This will give you a working directory that you can commit to, storing it for retrieval from any location.

Now set up your working directory. I will not give this level of directions every lab - this is just to remind you of the unix commands that accomplish these tasks. You may refer back to this lab if you forget in the future.

$  cd CNET-cs152-win-17
$  mkdir hw1
$  svn add hw1
$  cd hw1

Edit

We expect you to use vim (for editing) and clang (for compiling) this quarter, though there are many other tools available for code editing and C compilation. These two have the virtue of working entirely from the console. Among other desirable properties, this makes it painless to work on the CS network using vim and clang from a remote computer (such as your laptop, in your room, on a freezing winter night).

Here are a few words about each of these applications.

vim

Vim stands for "vi improved" and is an updated (though not recently) version of the classic editor vi. Vi (when you say this out loud, you say both letters individually: "v i") is a simple, lightweight, scriptable editor that has been in use since the 1970s. Please note that we will use the names vi and vim mostly interchangeably as we move forward (as is common practice in the world at large).

Vi has a modal interface, which is to say it has various modes you can be in (or not in) at any given moment. When you start vi, you are in command mode. To edit text, you need to switch to insert mode. You switch to insert mode by typing i, and you switch to command mode by typing the esc key.

You issue commands in command mode by typing a colon (:) and then one or more characters naming the command; for example, :q quits vi and :w writes the current file to disk (think of :w as "save").

At some point this week, but not during this lab period, you should go through vimtutor. This will take about 30 minutes and will give you practice with an assortment of vi tools and techniques. You can do so by opening a terminal and typing vimtutor. Today, you may use the editor of your choice.

An Example

Now let's go ahead and compile that code you saw in the pre-lab.

In order to practice editing and compiling, let's copy and paste functions.c into a new file with vim. First, bring up the code functions.c in your browser by clicking on the link.
Open a new file named functions.c in your terminal window.

prompt$ vi functions.c

Then place yourself in insert mode in vim (press 'i'), copy the code from the screen, and paste it into your file.
Then press <ESC> to get out of insert mode (and into command mode).
Finally, type :wq to write the file and quit vim.

Follow the same process with functions.h and main.c.

Compile

clang

You will compile your programs using clang, a popular open-source C compiler that ships with current Apple computers, like those we have in CSIL, and is furthermore available for free installation on other platforms.

Your program has three files - functions.h, functions.c, and main.c.
If a program has only one file, the compile line is the following:

$ clang myprogram.c
This is not the case for us, however. You have two choices - compile each part individually and combine at the end or compile in one step.
To compile in one step:
$ clang functions.c main.c

To compile separately, use the -c flag. That tells the compiler that you're just compiling a single file, not the entire thing. Instead of creating an executable, it only creates a .o file containing the compiled information for that one file. Thus, there are three steps: Compile functions.c, compile main.c, and link them together.
$ clang -c functions.c
$ clang -c main.c
$ clang functions.o main.o

If the compilation is successful, you'll see nothing at the terminal, but the compiler will have created an executable file named a.out. You can run the executable by typing ./a.out.

You can specify a different filename for the executable, other than the default name a.out, with the -o flag as follows:

$ clang -o go functions.c main.c
and then run it with ./go.

If your program includes math.h, depending on the system you're working on, you might need to include the compiler flag -lm to link in the math library. This flag appears as another option to the compile command, like so:

$ clang -lm -o go functions.c main.c
Since -lm is sometimes necessary and never harmful, you should make a habit of compiling with it whenever math.h is part of your program.

You can give command-line arguments to clang in standard UNIX style. We will spruce up the call to clang in this case to do two things: first, to be aggressive about warning the programmer about potential problems in the code, and second, to name the executable something other than the standard a.out. Try this command:

$ clang -Wall -o testprogram functions.c main.c
The option -Wall means "all warnings." You will come to appreciate these warnings; they save you a lot of time and toil.

Makefile

There is a compilation tool make that looks for a file named Makefile containing compilation instructions. You will now create a Makefile containing instructions on compiling the evidence tool in progress. Create Makefile and write the following into it:

testprogram: functions.h functions.c main.c
        clang -Wall -o testprogram functions.c main.c
The first line contains a target (testprogram) and dependencies (functions.h, functions.c, and main.c). If any of those files are newer than the executable, then it will recompile. If not, it leaves it as is. The second line contains the compile line. Please note that on the second line (after the line that starts with testprogram:), the first character is a TAB: exactly one of them. This is important; the Makefile is not well-formed without it. Having created this Makefile, you can now compile the "testprogram" executable by simply typing
$ make testprogram
$ ./testprogram
Try it!

Make is a language-agnostic tool; it doesn't care if it's compiling C, Racket or anything else. It has many more capabilities than we will discuss today or even this quarter. It is a powerful assistant in software development of all stripes. The more code you write, the more you will have occasion to use and appreciate it.


Compile Errors

When you are compiling, you may encounter compile errors. These prevent the compiler from creating an executable. There are a few keys to solving compile errors.
  • Start with the first error listed. Once the compiler gets confused, it may report things that aren't actually bugs. It is most useful to start with the first bug.
  • Look at the line number of the error. You can go to that line in vi by typing the number and G if you are in command mode. The error is on or slightly before that line. That is the line at which the compiler noticed the mistake - the mistake itself could be slightly earlier.
  • Read the error message slowly and carefully. Think of the compiler like a toddler with very sophisticated vocabulary but not sophisticated reasoning skills. That's exactly what it is. When you read the error, don't expect it to be exactly correct. Instead, think to yourself, "What could I have written to confuse the compiler into thinking this?"

Execute

Once you have compiled your code, you are ready to test it through running it. If you did not name it anything special, then you will run it with:
$ ./a.out

To stop a program that is running for too long, because of an infinite loop or for any other reason, type Ctrl-c in the terminal.

Debug

Once you start executing, you may find that one of your test cases has a result that does not match the expected result. You are now ready to move on to debugging. Think of debugging as an investigation. Let's say you lost your keys. You know you had your keys this morning, and now, 8 hours later, you notice you do not have your keys. The beginning and end is not enough information. You need to figure out all the places you went in order to think about where those keys might be. Likewise, with bugs, you need more information than the beginning and the end. You need to think about what the expected result is partway through the execution of the program, and then see if it is that result there (with a print statement). You can, in essence, use a binary search of your code to find your bug. Print out intermediate results during the program, and gradually narrow down when the execution goes differently than you thought it should.

When you are done, save the file. Then add it to your svn repository. This would be a good time to commit your work!

Learning Compile Errors

If you're lucky, you haven't hit any compile errors yet. However, if and when you do, you'll see that they are a bit cryptic at times. In order to familiarize yourself with some common error messages, you're going to intentionally introduce errors and then see what error messages result from them.

Before you start, copy your working files to new filenames so you don't ruin your working files.

$ cp main.c errormain.c
$ cp functions.c errorfunctions.c
You're going to be filling in a file. Make sure you do the following:
$ touch errors.txt
$ svn add errors.txt
This creates an empty file named errors.txt and then adds it to the repository. This way, you won't forget to add it!

Copy and paste the following list into a file named errors.txt. For each problem, it first tells you what error to introduce into one of the files. Once you do this, compile the code again. Remember to use these files names - errormain.c and errorfunctions.c. Then copy and paste the error message into the file on the line starting with #). Then correct the code before moving to the next one.


1. Comment out #include "functions.h" from errormain.c (place "//" before it)
1)

2. Declare the same variable name twice
2)

3. Remove a variable declaration
3)

4. Misspell a variable name or function name
4)

5. Remove a closed curly brace
5)

6. Remove the line #include from errormain.c
6)

7. Remove a semi-colon from the end of one of the lines
7)

When you are done, save the file. If you didn't already do so, then add it to your svn repository. This would be a good time to commit your work!
$ svn commit -m "finished errors.txt"

Submit

At this point, you should have done the following:
  • Checked out your repository
  • Created a folder named hw1 in your repository and run svn add hw1
    $ svn add hw1
  • Created five files and filled in the proper information: functions.h, functions.c, main.c, errors.txt and Makefile inside your hw1 directory.
  • $ svn add functions.c functions.h main.c Makefile errors.txt
  • Compiled your executable manually and with the Makefile
  • Executed your code to make sure it runs properly and inspected the results.
  • Introduced bugs and placed results in errors.txt
  • Committed everything
  • $ svn commit -m "hw1 warmup complete"
Now you're ready to write your own functions!!! Move on to the hw1 description.