CS 61C (Fall 2007)

Lab Assignment 1

Goals

These lab exercises are intended to show you how to run a C program on the EECS instructional computers, to introduce you to the gdb debugger, and to get you thinking about the internal representations of characters and numbers.

Reading

K&R: Sections 1.1-1.5, 1.7, 1.8, all of chapter 2 except material on arrays, sections 3.1-3.7 except material on arrays, sections 4.1-4.2 and 4.8-4.10 and sections 5.1-5.2.

The document "An Introduction to Using GDB Under Emacs" (a copy should be available near your workstation in 271 Soda).

Initial preparation

First, find a partner. You will be working with one or two partners in each lab section. For the first few weeks, these will be different classmates, to allow you to find people in your lab section with whom you work most productively.

Pick up an account form from your lab t.a. Login to the corresponding account. Then change your password: first give the command "ssh update"—all password changes are done on the "update" computer—then give the "passwd" command. Logout from update—you should still be logged in on the workstation in 271 Soda—and copy the directory ~cs61c/files/lab/1 to your home directory via the command "cp -r ~cs61c/files/lab/1 ." (that's a dot at the end).

Give the command "alias" to the shell to verify that the options "-Wall", "-g" and "-std=c99" will be in effect every time you give the "gcc" command. "Wall" means "Warn about ALL recognized irregularities"; "-g" causes gcc to store enough information in the executable program for the gdb debugger to make sense of it; and "-std=c99" will ensure you're using a modern dialect of C (C99). Warn your T.A. if these options do not appear in an alias entry for gcc.

Exercise 1 (2 points)

Part a

C's printf function is a general-purpose output formatting function. Its first argument is a string of characters to be printed, with each "%" indicating where one of the other (second, third, ...) arguments is to be substituted, and in what form it is to be printed. (Page 154 in K&R contains a table of format specifications used with printf.)

Normally, the format specification matches the type of the corresponding argument ("%d" is used to print decimal values, "%c" to print characters, and so on). C doesn't check that they match, however. For example, the code below (available online at ~cs61c/files/lab/1/output.c) prints an 'F'. Explain why.

	#include <stdio.h>
	int main ( ) {
		int n;
		n = 70;
		printf ("%c\n", n);
		return 0;
	}

Part b

Fill in the blank in the following C program, also in ~cs61c/files/lab/1/output0.c, so that its output is a line containing 0. Don't change anything else in the program.

	#include <stdio.h>
	int main ( ) {
		int n;
		n = _____;
		printf ("%c\n", n);
		return 0;
	}

To verify your answer, compile the program using the "gcc" command, then run it with the command "a.out". Show the result to your t.a. for checkoff.

Part c

The program ~cs61c/files/lab/1/mysteryout apparently produces a blank line as output. Find out what it really prints using the od (octal dump) command; man od will give you information about how it works.

Exercise 2 (2 points)

The program ~cs61c/files/lab/1/buggy.base2.print.c (listed below) is intended to print the binary (base 2) representation of the unsigned value stored in the variable numToPrintInBase2. It has bugs.

	#include <stdio.h>
	int main ( ) {
		unsigned int numToPrintInBase2 = 1431655765;	/* alternating 1's and 0's */
		unsigned int exp = 1;
		int k;	/* can't declare variable in a loop header */
		/* Compute the highest storable power of 2 (2 to the 31th). */
		for (k=0; k<31; k++) {
			exp = exp * 2;
		}
		/* For each power of 2 from the highest to the lowest,
			print 1 if it occurs in the number, 0 otherwise. */
		for (k=31; !(k=0); k--) {
			if (numToPrintInBase2 >= exp) {
				printf ("%d", '1');
				numToPrintInBase2 = numToPrintInBase2 - exp;
			} else {
				printf ("%d", '0');
			}
			exp = exp / 2;
		}
		printf ("\n");
		return 0;
	}

Follow the steps below to find the bugs. These steps should give you experience with useful features of the gdb debugger.

  1. Compile the program and run it with gdb as described in the "An Introduction to Using GDB Under Emacs" document. This will involve splitting your emacs window in half, then running gdb in the bottom half. Observe the behavior, then get back to gdb by typing control-C twice.
    1. Copy the file buggy.base2.print.c to your directory, then edit it with emacs.
    2. Split the window using control-x 2.
    3. In the window with the code, type meta-x compile; backspace over the make command, and replace it with 'gcc buggy.base2.print.c'
    4. In the other window, where you want to run gdb, type meta-x gdb, then complete the command by typing a.out (note do not replace the command, simply add a.out to the end of it).
    5. Move the cursor back to the other window, on the line at which you want to set a breakpoint.
    6. Move the cursor back to the gdb window segment, click on the command prompt, and type run. Type control-c to regain control.
    7. Go back to the source code window segment, and continue with step #2 on the assignment.
  2. Set a breakpoint at the start of the second loop, then run the program again. Print the value of exp. Is this value right or wrong? Why? If it's wrong, correct it using the command "print exp = correctValue".
  3. Using the "next" command, single-step through the second loop for a couple of iterations. Print values of variables to gather information about what's going wrong.
  4. Go back to emacs to find and fix the bugs, changing as little of the program as possible. Then run the program again in gdb.

For checkoff, show the bug fixes to your T.A. and verify to him that you know how to run a program from emacs under gdb's control.