1. Goals for this week

  • Learn how to write C library code, and how to link it into programs that use it

  • Learn what .c and .h files are

  • More practice with strings in C (and using the readline library)

  • Practice with Dynamic 2-D arrays (Method 2: the programmer friendly but space inefficient, way)

2. Starting Point Code

Start by creating a 11 directory in your cs31/weeklylabs subdirectory and copying over some files:

$ cd ~/cs31/weeklylabs
$ mkdir week11
$ cd week11
$ pwd
$ cp ~newhall/public/cs31/week11/* ./
$ ls

3. Writing a C library

We are going to learn how to write a C library and how to use it in a program.

First, let’s look at some documentation about Libraries in C. We are going to look at the "CREATING AND USING YOUR OWN LIBRARY CODE" part of this. This content is also available in in Section 2.9.6 of the textbook.

Next, lets look at an example C library implementation, starting with the library interface in mylib.h, and the implementation in mylib.c. Then let’s look at an example program that uses it (prog.c), and try compiling and running it.

Phases of Compilation contains some information about the preprocessor and other compilation phases.

4. make and Makefiles

We have been using make and Makefiles all semester. When make is run it reads the Makefile to find the rules for compiling or for cleaning up compiled files.

We are not going to talk about make today, but if you are curious, here is some documentation about writing makefiles: Makefiles. After looking this over, open in vim the Makefile you copied over with today’s in-class code and see if you understand what it is doing. I’ve added some comments to describe some parts of it. Also, fancyMakefile is another version of a Makefile for building the prog executable. It uses some more advanced features of make. You could try compiling using it by running make -f fancyMakefile, and make clean -f fancyMakefile.

5. Strings and chars in C

Let’s look at the file str.c. This code contains some examples of manipulating strings (and individual chars in a string) in C.

Remember, that in C, a string is an array of char with a special terminating null character '\0' that signifies the end of the string. The array of chars can be statically or dynamically allocated (by calling malloc). One thing to remember is to allocate enough space for the terminating null character.

This code also shows an eample of using the readline library to read in a string entered by the user. There is some documentation about the readline library here: The readline library. Let’s look at the man page for readline and see what it does, how to call it, and what it returns:

man readline

The call to readline returns a string (allocated in heap space) to the caller containing the contents of the input line. It is the caller’s responsibility to free this returned string.

Let’s take a look at this code and see what it is doing. Note its uses the ctype and string library functions. C string library functions assume that the caller has allocated space for the result string (note the call to strcpy).

Some example use of string library functions:

  strcmp, strlen, strcpy, strstr, strchr,

Some example use of C library functions for testing char values:

  isalnum, isdigit, isspace

Chapter 2.6.3 contains information about string library and C library functions for char values.

Their man pages will also give more information about how to use them.

man strcmp

man isspace

5.1. Try out

  • In another window, compile and run this program to see what it is doing. Note when it is manipulating the individual char in the string (array of chars) and when it is treating it as a string (using strcpy, strlen).

Try running with some different input strings, for example:

hello 1 2 3
    hello   1   2   3
!@  hello  x%
  • Next, try implementing code to create a substring for the first token in the str string:

    1. search for the start of the first token (the first non-space char)

    2. continue processing chars until find end of first token (the first space char following sequence of non-spaces)

    3. change the char at the end of the first token to '\0'

    Make the substr pointer point to the beginning of the first token and try printing it out. One way to set a pointer to point to any bucket in an array is:

    ptr = &(array[i]);

    Compile and try running with different input strings and see if it works.

6. Dynamically allocated 2-D arrays (an array of arrays)

We are going to look at an example of the "Method 2" way of dynamically allocating a 2D array. This way supports [i][j] indexing, but it is less memory efficient than the single malloc ("Method 1") way of allocating 2D arrays.

This method allocates a 2D array as an array of arrays. In the outer array (of row dimension) each element stores the base address of an inner array ( of column dimension) of values in each row of the 2D array. Section 2.5 of the textbook describes this, and includes an figure of what this version of a 2D array looks like in memory.

This type of 2D array is used for the argv 2D array of char that contains the command line argument values passed to execvp (or as a parameter to main).

In this method, the programmer makes num_rows + 1 calls to malloc:

  1. one malloc to dynamically allocate an array of type * that will store the base address of an array to store each row’s values.

  2. num_rows mallocs to dynamically allocate arrays of type to store the values in each row of the 2D array. The base address of each is stored in the ith bucket of the outer array.

The variable storing the base address of the outer array is a type **: a pointer to a storage location that stores a type * (which stores the base address of an array of type). For example:

int **2d_array;
char **2d_chararr;
  • Let’s look at the example in twoD_method2.c.

  • Next, try implement the two functions that it calls.

  • Next, try adding code to free its dynamically allocated space.

  • Next, run in valgrind and see if you have any memory access errors:

    valgrind ./twoD_method2

7. Handy References