CSC161 2011S Imperative Problem Solving

Laboratory: Libraries

Summary:

Prerequisites: Familiarity with C, up through functions.

Preparation

a. Create a directory for this lab. I'd recommend csc161/labs/libraries.

b. In that directory, create a Makefile with the following lines

CFLAGS=-Wall
LDFLAGS=-lm

Exercises

Exercise 1: A Simple Library

a. Create a file, mylib.c, that contains one function, int average (int values[], int size), which computes the average of an array of values.

b. Obviously, one thing you'd like to do is test that code. We might start with a simple test. Create a file test1.c, with the following code:

#include <stdio.h>

int
main ()
{
  int values[] = {1,2,3};
  printf ("%d\n", average(values, 3));
  return 0;
} // main

c. One way to compile the two files together is by using both source files. Write

% cc -Wall -o test1 test1.c mylib.c

Note: You'll probably get a warning message because test1.c does not officially know about average. That's okay, it's just a warning.

d. Run the resulting file (./test1).

e. Remove test1.

Exercise 2: Forgetting Parts

You'll note that our program has two source files: test1.c contains the main function and mylib.c contains the average function that gets called by main. What happens if we try to use them separately?

a. What do you expect to happen if you compile test1.c without including mylib.c?

b. Try it

make test1

c. What do you expect to happen if you compile mylib.c without including test1.c?

d. Try it

make mylib

Exercise 3: Separate Compilation

It turns out that we're often better off compiling each file separately. That way, if we make a change to one file, we reduce the work required to rebuild our program - we only need to recompile that one file and then join the compiled files together.

a. Create an object file from mylib.c with

% make mylib.o

b. Create an object file from test1.c with

% make test1.o

c. Link the two files together with

% cc -o test1 mylib.o test1.o

d. Confirm that the resulting program works as expected.

e. Remove test1 and both .o files.

Exercise 4: Better Makefiles

The previous exercise gives you a lot of steps to remember. First you have to make each .o file. Then you have to link them together. (Okay, maybe it's not that many steps.) How do you remember the steps? Often, we just tell make about them.

a. Add the following lines to your Makefile. (Note that you must use a tab for the indented line.)

test1: test1.o mylib.o
        gcc -o test1 test1.o mylib.o

These lines tell make two different things:

b. Type

make test1

c. Run test1.

d. Make an update to test1.c (e.g., use a different array).

e. Make test1 again. What steps were redone? What steps were not redone?

Exercise 5: Fun with Headers

Okay, we've been getting a lot of warnings about the compiler not knowing enough about average. Let's solve that problem.

a. Create a file mylib.h with the following line.

int average (int values[], int count);

b. At the top of mylib.c, add the line

#include "mylib.h"

c. At the top of test1.c, add the line

#include "mylib.h"

d. Remake your program and verify that the warning has disappeared.

Exercise 6: More Fun With Headers

Suppose we made a mistake in the header. What will the effect be?

a. Update mylib.h so that it suggests that average has a third parameter.

b. What do you expect to happen when you remake test1?

c. Check your answer experimentally.

d. What happened? Well ... make didn't know that a change to mylib.h was supposed to require recompilation. So you need to tell it so. Add the following lines to your Makefile.

mylib.o: mylib.h
test1.o: mylib.h

e. Now, what do you expect to happen when you remake test1?

f. Check your answer experimentally.

g. We hope that you discovered that the program will not compile with the mismatched errors. So, correct the header in preparation for the next exercise.

Exercise 7: Choosing Between Libraries

One of the reasons we use separate files is that it lets us swap the implementations of different functions.

a. Create the file yourlib.c with the following lines

#include "mylib.h"

int
average (int values[], int size)
{
  // The average grade is a B, and a B is an 85.
  return 85;
} // average

b. Add lines to your Makefile that link yourlib.c and test1.o and call the result test1a.

c. Make test1a.

d. Run the program.

Exercise 8: Reusing the Library

Consider the following program.

#include <stdio.h>
#include <stdlib.h>
#include "mylib.h"

int
main (int argc, char *argv[])
{
  int size = argc - 1;	// The size of our integer array
  int nums[size];	// Our integer array
  int i;		// Everyone's favorite counter variable

  for (i = 0; i < size; i++)
    nums[i] = atoi (argv[i+1]);

  printf ("%d\n", average (nums, size));

  return 0;
} // main

a. Save it in the file average.c.

b. Update your Makefile to compile this and link it with myutils.o so that the resulting program is called ave.

c. Make and test the resulting program.

Exercise 9: A Shared Variable

Note that we are also supposed to be able to share variables between files. Let's try doing so.

a. Add the following to myutil.h

int reset ();
int increment ();
int counter;

b. Add #include <stdio.h> to the top of myutil.c (unless you already have it there).

c. Add the following to myutil.c

int
reset ()
{
  counter = 0;
} // reset

int
increment ()
{
  ++counter;
  printf ("Counter is now %d.\n", counter);
} // increment

d. Create a new program, test2.c with the following lines:

#include <stdio.h>
#include "myutil.h"

int
main ()
{
  counter = 5;
  printf ("Counter is now %d.\n", counter);
  reset ();
  printf ("Counter is now %d.\n", counter);
  increment ();
  printf ("Counter is now %d.\n", counter);
  counter = 10;
  increment ();
  printf ("Counter is now %d.\n", counter);
} // main

e. Add lines to your makefile to make test2 from mylib.c and test2.c.

f. What output do you expect when you run the program?

g. Check your answer experimentally.

h. As you may have discovered, what you've done is accidentally create two versions of the variable counter, one in mylib.c, one in test2.c. How do we share the variable? We use the extern prefix in the declaration in mylib.h.

extern int counter;

i. What do you expect to have happen if you make this change?

j. Check your answer experimentally.

k. You've now discovered that you need at least one declaration of counter. Add that to mylib.c.

For Those with Extra Time

If you find yourself with extra time (something I consider unlikely), begin working on the current assignment.

 

History

Monday, 4 October 2010 [Samuel A. Rebelsky]

Friday, 4 March 2011 [Samuel A. Rebelsky]

 

Disclaimer: I usually create these pages on the fly, which means that I rarely proofread them and they may contain bad grammar and incorrect details. It also means that I tend to update them regularly (see the history for more details). Feel free to contact me with any suggestions for changes.

This document was generated by Siteweaver on Fri Mar 4 11:36:42 2011.
The source to the document was last modified on Fri Mar 4 11:36:40 2011.
This document may be found at http://www.cs.grinnell.edu/~rebelsky/Courses/CSC161/2011S/Labs/libraries-lab.html.
A PDF version of this document may be found at http://www.cs.grinnell.edu/~rebelsky/Courses/CSC161/2011S/Labs/libraries-lab.pdf

Samuel A. Rebelsky, rebelsky@grinnell.edu

Copyright © 2010 Samuel A. Rebelsky. This work is licensed under a Creative Commons Attribution-NonCommercial 2.5 License. To view a copy of this license, visit or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.