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 -
Practice with dynamically allocated 2-dimensional arrays (Method 2: The Programmer-Friendly Way)
-
Practice with strings in C (and using the
readline
library) -
Learn to extract the first token from a string
2. Starting Point Code
Start by creating a week11
directory in your WeeklyLabs
subdirectory
and copying over some files:
$ cd ~/cs31/WeeklyLabs
$ mkdir week11
$ cd week11
$ pwd
/home/you/cs31/WeeklyLabs/week11
$ cp ~newhall/public/cs31/week11/* ./
$ ls
fancyMakefile Makefile mylib.c mylib.h prog.c str.c twoD_method2.c
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" section of that document. This content is also available 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
.
Open mylib.h
and mylib.c
in an editor.
Next, open prog.c
in an editor: this program uses the mylib
library.
Let compile and run it.
$ make
$ ./prog
If you are interested, you can read about the phases of compilation, which includes information about the preprocessor and other compilation phases.
4. Make and Makefiles
We are not going to talk about this in lab, but knowing something about make and makefiles will be useful in some upper-level CS courses.
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, and covered in more depth in
Appendix 2, 17.2:
make and Makefiles. After skimming that documentation, use an editor to open
the Makefile
you copied over with today’s in-class code and see if you
understand what it is doing. There are some extra comments to describe some
parts of it.
Also included in today’s in-class code is fancyMakefile
. This is another
version of a Makefile
for building the prog
executable that uses some more
advanced features of make
. You can try compiling using it by
running make -f fancyMakefile
, and make clean -f fancyMakefile
.
5. 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 method supports
[i][j]
indexing, but it is less memory efficient than the single
malloc
("Method
1") way of allocating 2D arrays that we used in the Game of Life lab.
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 as a parameter to
main
(and as we’ll see in class, the parameter passed to execvp
).
In this method, the programmer makes num_rows + 1
calls to malloc
:
-
one
malloc
to dynamically allocate an array oftype *
that will store the base address of an array to store each row’s values. -
num_rows
mallocs
to dynamically allocate arrays oftype
to store the values in each row of the 2D array. The base address of each is stored in theith
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;
-
The example in
twoD_method2.c
shows how to allocate space for a two-dimensional array using this method. -
You may want to try implmenting the code in this function (or think about how you would do it) as practice for this week’s lab:
-
try to implement the two functions with TODO comments in them
-
try adding code to free the dynamically allocated space
-
run your solution in valgrind to make sure you have no memory access
-
errors:
valgrind ./twoD_method2
-
6. 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.
In C, a string is a char
array with a 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 shows an example of using the readline
library to read in a string
entered by the user. You can read
some
documentation on the readline library for further information, or you can look
at the man page for readline
and see what it does, how to call it, and see
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
).
The C string library contains a number of useful functions, including:
strcmp, strcpy, strlen, strcat, strchr
The ctype library contains functions for testing char values:
isalnum, isdigit, isspace
-
Chapter 2.6.3 has more information about the string library.
-
and C library functions for char values from 2.6.3.
The man pages for these functions will also give you more information about how to use them:
$ man strcmp
$ man isspace
6.1. Try it 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%
7. Extracting the first Token
Part of the next lab assignment requires that you parse a string into its
substring string tokens. A string token consists of one or more characters, excluding whitespace and control characters. For example, the string:
"hello there! 123"
has three string tokens:
"hello"
, "there!"
, and "123"
.
-
Follow the instructions in the
TODO
section of thestr.c
file. Try implementing code to create a substring for the first token in the string you typed instr.c
:-
Search for the start of the first token (the first non-space char). Save the index of this character in the string in the variable called
tok_start
. -
Continue through the string until you find the end of first token (the first whitespace character after the start of this token). Save the index of this character in the string in the variable called
tok_end
. -
malloc
space to hold all of the characters fromtok_start
up totok_end
, saving a space for the'\0'
character. -
Copy all of the characters from the original string from
tok_start
totok_end
into the new string, and be sure to add a'\0'
at the end.
The result should be that the
substr
pointer points to a string equal to the first token ofstr
. After you’ve extracted this token, print it out.Compile and try running with different input strings and see if it works.
-
8. Lab Intro: Parsing the entire command line
Proceed to Lab 9. For this lab you will implement the parsecmd library that you used in the shell lab.
9. Handy References
-
-
C arrays, strings and the string library (Chapt 2.5, 2.6)
-
C dynamically allocated 2D-arrays (Chapt 2.5.2 Method 2)
-
Writing C libraries (Chapt 2.9.6)
-
Command line arguments (Chapt 2.9.2)
-
make and Makefiles (Appendix 2, 17.2)
-
-
C programming
-
C debugging
-
Chapter 3 on gdb and valgrind
-
Unix