1. Goals for this week

  • Practice compiling and running C programs: gcc and using make.

  • Practice with arrays in C.

  • Input in C: scanf for reading from stdin, and our read_file library to read from a file (used in the Lab2 assignment).

  • Learn some basic gdb debugging commands. We won’t have time to learn all of gdb this week, but we’ll see some debugging features beyond using gdb as a calculator.

1.1. Getting your warm-up code

Both you and your partner should clone your Lab2 repo into your cs31/labs subdirectory:

  1. get your Lab2 ssh-URL from the CS31 git org. The repository to clone is named Lab2-user1-user2, where user1 and user2 are the user names of you and your Lab 2 partner.

  2. cd into your cs31/labs subdirectory:

    $ cd ~/cs31/labs
    $ pwd
  3. clone your repo

    $ git clone [your_Lab2_repo_url]

There are more detailed instructions about getting your lab repo from the "Getting Lab Starting Point Code" section of the Using Git for CS31 Labs page.

1.2. Test sharing changes to your joint repo

As you and your partner work on your joint lab solution, you will want to push and pull changes from/to your local repos to/from the master repo.

As your start each lab assignment, it is good to first test out that you have both successfully cloned your shared repo, and that you can successfully share code by pushing a small change and pulling a small change made by your partner. We will practice this together in Wednesday lab. You can also follow the directions in the "Sharing Code with your Lab Partner" section of the Using Git for CS31 Labs page.

1.3. Warm-up Files

Cloning the repository will give you a warmup-code folder with the following files:

$ cd Lab2-yourgroup/warmup-code
$ ls
 arrays.c  Makefile  testprog.c  types_scanf.c test_readfile.c
 readfile.c readfile.h

2. C compiling and running

First, let’s remind ourselves of the basics of compiling and running C programs.

Now, let’s try it out on one of the files you copied over (we will use the -g and -o outfile options to gcc):

gcc -g -o arrays arrays.c
./arrays

With the code you copied over is a Makefile. In this file are rules for compiling executables from the .c source files that are executed by typing in the make command. make is very convenient way to compile without having to type in a long gcc command every time, you just need to type make:

make         # this will compile all files as specified by the all: rule

make clean   # this removes all files generated by make (they can be rebuilt)

3. Arrays

Together we are going to start by looking at arrays.c, which contains examples of how to use (and abuse) arrays in C.

Arrays are composite data types that contain elements all of the same type. In arrays.c take note of the following:

  • array declaration: if we declare an array of 5 int s. Since each int is 4 bytes, the array size is 5 x 4 = 20 bytes.

  • initializing an array: note that non-initialized arrays contain garbage values!. You should always make sure to initialize an array before performing operations on it.

  • printing the elements of an array: Note that C does not keep track of the array limits!. It is your responsibility to make sure your print statements don’t go off the end of an array.

In this program, we see also see how for-loops are defined in C.

4. Input in C

We are going to look at two examples of reading in input values into a C program.

  1. The first example, in types_scanf.c, shows examples the scanf function from the C stdio library to read in different type values from the users.

    Note that scanf needs to know the memory location of where to put the values read in, and we use the & operator on a variable name to pass this location to scanf. For the Lab 2 assignment you will need to do something similar when you call library functions to read in values from a file. We’ll talk much more about what that ampersand means as we build up our C programming skills in future assignments.

  2. The second example, in test_readfile.c, shows some examples of reading in values from a file using the C read_file library that the CS31 instructors wrote (implemented in readfile.c and readfile.h. + Information about using the library is documented in comments in the .h file. Let’s open that in one window, and open test_readfile.c program in another:

    vim readfile.h
    
    vim test_readfile.c

    test_readfile.c has some code to open an input file, given as a command line argument when run, and to read in an int value. It is run like this:

    ./test_readfile <inputfile>    # specify the name of an inputfile on the command line
    
    # examples:
    ./test_readfile values_int       # run testfile with values_int as its inputfile
    ./test_readfile values_float       # run testfile with values_float as its inputfile

    Looking at the contents/format of the values_int and values_float files:

    cat values_int
    cat values_float

    and refering to the library interface commented in readfile.h, add calls to readfile library functions to the test_readfile.c program to read in the next few values from an input file. Then compile and try running.

    vim test_readfile.c
    make
    ./test_readfile values_int
    ./test_readfile values_float

5. GDB intro

gdb is the gnu debugger for C and C++ programs. Last week we used gdb as a calculator and converter, but it is normally used to help debug programs. Over the course of the semester will will use gdb and learn more and more features. Today, we will learn just a few basics.

To use the debugger, you usually want to compile your C program with the -g flag to add debugging information to the a.out file (this allows gdb to map binary machine code to C program code that the programmer understands).

$ gcc -g -o arrays arrays.c

The makefile already has this rule for us, so let’s just run make.

Next, we will run the executable file inside the gdb debugger:

$ gdb ./arrays

The first thing we get is the gdb prompt (our program has not yet started). Typically we will set a break point at main. A breakpoint tells gdb to grab control at a certain point in the execution, in this case right before the first instruction in main is executed:

(gdb) break main
Breakpoint 1 at 0x6b2: file arrays.c, line 4.

Next, we will enter the run command at the gdb prompt to tell gdb to start running our program:

(gdb) run

The run command will start your program running, and gdb will only gain control again when a breakpoint is hit.

There are a few other main gdb commands we will learn today, the first is the list command that lists the C source code around the point where we are in the execution:

(gdb) list

list with a line number lists the source code around that line:

(gdb) list 10

The next (or just n for next), which tells gdb to execute the next instruction and then grab control again:

(gdb) next    # this will start the for loop execution
(gdb) next    # this will initialize i = 0

The print command can be used to print out a value of a program variable or expression:

(gdb) print i
$1 = 0

cont tells gdb to let the program continue running. Since we have no more breakpoints it will run until termination.

(gdb) cont
Continuing.
a[0] =  0
a[1] =  1
a[2] =  4
a[3] =  9
a[4] =  16
a[5] =  25
....
[Inferior 1 (process NUM) exited normally]
(gdb)

Now lets add a breakpoint at line 16 of our code and rerun the program:

(gdb) break 16
Breakpoint 2 at 0x718: file arrays.c, line 16.

The run command starts the program’s execution over from the beginning. When re-run, the breakpoint at the beginning of the main function will be hit first (list will display the code around the breakpoint).

(gdb) run

Breakpoint 1, main () at arrays.c:4
4	int main() {
(gdb) list

Type cont to continue execution from breakpoint in main and to reach our next breakpoint on line 16.

(gdb) cont
Breakpoint 2, main () at arrays.c:16
16	  for (i=0; i<=15; i++){

(gdb) cont

When the program reaches the breakpoint we could print out the values in the array:

(gdb) next
(gdb) print a[i]
(gdb) next
...

After continuing the breakpoint in mystery is hit next (Breakpoint 2), let’s step through some of the mystery function’s execution, and print out some of its parameters and locals.

We can use the print command to print out expressions on the variables in the program.

(gdb) print a[i] + 2

The where or bt command list the call stack:

(gdb) where

When you’re done using gdb, type the command quit.

(gdb) quit
$

If you use gdb to help you debug the lab this week, you will need to give the run command a commandline argument that is the file name:

(gdb) break main
(gdb) run floats.txt

In general, for programs with command line arguments, simply list the arguments after the run command, for example to run with 3 command line arguments, 6, 4, and hello, do the following:

(gdb) break main
(gdb) run 6 4 hello

We will talk more about C and gdb over the course of the semester.

6. Lab 2 Intro

Lets talk through the next Lab Assignment, where you will implement a C program that, among other things, performs a sorting task.

7. Handy Resources