You are on page 1of 51

1/9/14 8:07 PM Introduction

Page 1 of 1 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/intro.html
Introduction
In CS 9C, you learn to program in C. You are assumed to have had previous programming
experience, in particular with the construct called a pointer in Pascal or Scheme or an address in
assembly language. CS 3 or 3S or IDS 110 probably does not provide sufficient experience for
this course; we recommend that you take CS 9B to acquire more experience.
Course material consists of quizzes, which test your knowledge of language and low-level
conceptual details, and programming assignments, which exercise your overall command of the
language. This volume supplies a framework for the course. It contains the following:
Study modules. Each module focuses on a particular programming topic.It provides references to
textbook material describing the topic,and suggests exercises for self-study. The study guides
reference the following texts and documents.
Beginning with C, Ron House (PWS Publishing Company, 1994).
The C Programming Language, second edition, B.W. Kernighan and D.M. Ritchie
(Prentice-Hall, 1988).
Programming assignments. Each one has a header page (this tells you the title and related topics)
that is followed by the actual assignment.
Sample quiz questions, with solutions. These help you prepare for the quizzes.
Comments on the texts
The House book is aimed at programmers without a lot of experience. If you have had only a
couple of courses prior to CS 9C, or you haven't written many programs that use pointers, you
will benefit from the explanations and extended examples in this text.
The Kernighan and Ritchie book (affectionately known as "K and R") is the "bible" for the C
language. It was written for experienced programmers; once you learn C, you will find it an
excellent reference.
1/9/14 8:08 PM Structure of quizzes and programs in CS 9C
Page 1 of 1 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/course.org.html
Structure of quizzes and
programs in CS 9C
The following table outlines the relationship between quizzes and programs. All the material for
a particular grouping should be completed before material in the next grouping; however, you
must complete the corresponding program before taking any quiz.
group programs quizzes
a
Orientation
Introduction
Debugging

Fundamentals
Functions and argument pointers
b Abstract data types with arrays
Arrays, structures, and files
General pointers
c Abstract data types with trees Linked structures
For information about deadlines, consult the "Information and Regulations" document.
1/9/14 8:09 PM Program Introduction
Page 1 of 4 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.intro.html
Program Introduction
This programming assignment introduces you to C: variables and computation, functions and
parameters, and control structures. (You are allowed to use arrays as well if you want. However,
they are not required, nor are they necessary to solve the problem)
The C compiler provided on the EECS instructional computer accounts is named gcc. It comes
with a debugger gdb, which not only is a great debugger but has an extensive online help facility.
It supports ANSI Standard C as described in House and the second edition of Kernighan and
Ritchie. Use gcc to compile the program piglatin.c for this assignment as follows:
gcc -g -Wall -o piglatin piglatin.c
(On the EECS instructional computers, the gcc command is probably set up to supply the "-g"
and "-Wall" information automatically. To make sure of this, type
alias
to the UNIX shell and look for an entry for gcc.)
If the program contains no syntax errors, this command will produce an executable file named
piglatin. To run the program under control of the debugger, type the command
gdb piglatin

Running your program in this way is useful to simplify the task of tracking down your execution
errors; for example, if your program crashes, gdb will tell you the line number where the
problem occurred. You'll learn more about gdb in the next programming assignment.
Readings
House, chapters 1 through 8 except material in chapters 3, 5, and 7 on arrays.
Kernighan and Ritchie, chapters 1 through 4 except sections 1.9, 1.10, 3.8, 4.3, 4.5, 4.6, 4.7,
4.10, 4.11.2, and 4.11.3. You will not be tested on material on arrays in chapters 2 through 4.
The section "Before You Begin ..." available online in the self-paced course web site (for
students who are not familiar with EECS computing facilities).
The section "C Style Examples" later in this document.
Related quizzes
Fundamentals of C
CS 9C programming assignment 1
1/9/14 8:09 PM Program Introduction
Page 2 of 4 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.intro.html
Pig Latin
Background
Pig Latin is a language parents speak to each other when they don't want their children to
understand them. Each English word has a Pig Latin translation; you produce it as follows.
1. If the English word begins with a vowel ("a", "e", "i", "o", "u"), add "yay"to the end of the
word to produce the Pig Latin translation.
2. If the English word begins with a consonant (a non-vowel), move all leading consonants to
the end of the word and add "ay" to produce the Pig Latin translation. You should treat the
letter `y' as a vowel when it occurs after the first character in a word. You should also treat
the letter pair "qu" together as a consonant. Here are some examples.
English Pig Latin
yes esyay
example exampleyay
bygone ygonebay
test esttay
quiz izquay
strip ipstray
trips ipstray
schnitzel itzelschnay
rhyme ymerhay
Problem
Write a program in C to read a word from standard input and print its Pig Latin translation on a
line by itself on standard output. You may assume that an English word starts with no more than
four consonants.
Miscellaneous requirements
Guidelines for indenting, commenting, etc. are indicated in the section "C Style Examples".
Follow them.
C code is rather dense. Thus your functions should be small, certainly at most a screenful of
code.
Your program need not use arrays. You may assume that an English word starts with no more
1/9/14 8:09 PM Program Introduction
Page 3 of 4 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.intro.html
than four consonants. (This assumption makes it possible to avoid arrays.) You may also assume
that each "q" is followed by a "u". Test your program at least on the examples given above.
System information
The line #include <stdio.h> at the start of your program will allow you to use the predefined
constant EOF and the getchar and putchar routines for input and output.
There is a program called unpig in the ~cs9c/lib directory on your class account. After reading
a word, unpig prints all possible English words (and a few non-English "words") that have that
word as a Pig Latin translation. You may use unpig to check your work by piping your output
into it. (unpig doesn't quite work correctly for words starting with "qu", however.)
Generating a transcript of your program execution
For this and all remaining assignments, you are required to bring a transcript of your interaction
with your program to the Self-Paced Center for grading. One way to create such a transcript on
UNIX is to use the script program, which saves everything you do on the terminal in a file,
called typescript, until you type the command exit. After you are done, you can get a paper
printout of this file by using the lpr command. Here is an example of using the script and
lpr commands for this assignment:
% script
Script started, file is typescript
% cat prog1.c
... (your program listing) ...
% gcc prog1.c
% a.out
yes
esyay
% a.out | unpig
strip
ripst
trips
strip
pstri
% exit
% Script done, file is typescript
Everything that has appeared on the terminal between the script command and the exit
command has been saved in the file called typescript. You can now type lp typescript to get
a paper printout to bring in to the Self-Paced Center after you have done the rest of the
assignment.
Do not type another script command without first typing exit.
Do not use an editor when you are using script. While this does no harm, it does put bizarre
characters into the typescript file that cannot be displayed properly. If you do this your printout
1/9/14 8:09 PM Program Introduction
Page 4 of 4 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.intro.html
will end up being very garbled.
Helpful hints
C gives you plenty of rope to hang yourself. To save your neck, you should spend time
decomposing the problem into manageable pieces (i.e. separate functions!) before trying to
code anything, and then test each piece separately. You may test your functions individually by
writing a tiny "driver" main ( ) that simply gets test data and calls the function.
Some aspects of C are sure to trip up the novice C programmer, for instance, the placement of
semicolons and parentheses, the need to "break" out of a case in a switch statement, and the
indexing of arrays. The compiler and run-time system are sometimes of little help in finding
these errors. Advice: Start with something simple, get it working, and add small pieces to it one
at a time. Tutors will ask you, when you bring them bugs, "What was the last thing you did that
worked?" You should have a good answer.
Arrays are not necessary for this problem. (Why? If you need a hint, consider a program that
simply echoes characters from the standard input to standard output. How many variables does
that program need?)
Checklist
A satisfactory grade on this assignment requires the following:
Correctly working program, tested as suggested
Short functions
Good style and layout
Reasonable names for variables, functions, etc.
Loops and blocks indented according to the given guidelines
Informative comments accompanying every function
MJC, EL 8/95
1/9/14 8:12 PM QuizFundamentals
Page 1 of 3 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.fundamentals.html
Quiz Fundamentals
This quiz focuses on the aspects of the C language that are conceptually similar to those in other
procedural languages: variable declaration, expression evaluation, flow-of-control constructs,
and input/output. Three especially tricky aspects of C covered on this quiz are the difference
between = and ==, the difference between char and int values, and the representation of "true"
and "false".
Readings
House, chapters 1 through 6 except material in chapters 3, 5, and 7 on arrays. House omits the
type of the main function throughout; in contrast, we will always specify it as type int in
accordance with the C standard. (By convention, a return value of 0 from the main function
means successful completion; nonzero return values indicate some sort of error.)
Kernighan and Ritchie, sections 1.1 through 1.6; chapters 2 and 3 except material on arrays and
functions.
Suggested exercises
House, "short answer" self-test exercises and test questions in chapters 2 through 6 except
section 5.7 #2 and #7. You may also be asked to write small program segments.
Sample quiz
1. Suppose that an integer variable n contains the value 80. Fill in the blanks in the printf
statement below so that it produces the output
80% usually
means "excellent"
printf statement:
printf ("________", n);
2. Consider the program segment
int k;
k = getchar ( );
printf ("%d", k);
What gets printed if the user types a 2, then hits return?
3. The following program is intended to compute 5! = 120, but it prints 24 instead. What's
wrong with it?
int main ( ) {
1/9/14 8:12 PM QuizFundamentals
Page 2 of 3 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.fundamentals.html
int theNum, total;
total = 1;
theNum = 5;
while (theNum > 1) {
total *= --theNum;
}
printf ("%d", total);
return 0;
}

4. What would be the effect of substituting !(theNum = 1) for the while condition theNum >
1 in the main program of exercise 3?
5. Fill in the blanks in the code below to convert the while loop in exercise 3 to an equivalent
for loop.
int main ( ) {
int theNum, total;
total = 1;
for ( _____ ; _____ ; _____ ) {
total *= theNum;
}
printf ("%d", total);
return 0;
}
6. Write down the values for all variables appearing in each statement.
int main ( ) {
int x, y, z;
float a, b;
x = 3; y = 5.3; z = 2; x ____ y ____ z ____
a = 2.5; b = 3.14; a ____ b ____
/*1*/ x += y + a * z-b; x ____
/*2*/ a = b / (x%y + z) a ____
z += (x == y); z ____
/*3*/ x == (a = b); x ____
return 0;
}
Where do you need parentheses to have x assigned a value of 14 in the statement
labeled /*1*/? What then is the new value of a in the statement labeled /*2*/? What
is the new value of x in the statement labeled /*3*/?
7. Predict the output of the following program. Hint: only three lines get printed. (This is
somewhat more complicated than any of the actual quiz questions.)
int main ( ) {
char c;
for (c='a'; c<'g'; ++c) {
switch (c) {
case 'a': c += 2;
case 'c': c += 1;
case 'g': ++c;
1/9/14 8:12 PM QuizFundamentals
Page 3 of 3 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.fundamentals.html
printf ("%c\n" , c-- );
default: ++c;
}
printf ("*** %c\n" , c);
}
return 0;
}
1/9/14 8:13 PM Program-Debugging
Page 1 of 8 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.debugging.html
Program Debugging
No doubt the program for the previous programming assignment gave you some practice in debugging. This assignment will give you more. You are to find
some bugs we've installed in a program. gdb will again be helpful.
Readings
House, chapter 8; sections 9.1 through 9.4, 12.1, and 12.2.
Kernighan and Ritchie, material on arrays in chapters 1 through 4 that you didn't read for the "Fundamentals" quiz, plus sections 5.1 through 5.3. Material in
sections 1.10, 3.8, 4.3, 4.5, 4.6, 4.7, 4.10, 4.11.2, and 4.11.3 will not be covered.
Related quizzes
Simple strings and pointers.
Background
This assignment provides an introduction to some of the major features of gdb (the GNU debugger) by leading you through the debugging process of a
slightly buggy program. A debugger allows the programmer to stop a program in the middle of its execution so that he or she may observe how the program
branches and executes. Debuggers can help speed the process of isolating and correcting bugs.
Follow the instructions outlined in the assignment in order to debug the provided program and answer the questions throughout the assignment on a separate
piece of paper. You will be required to present the corrected code, script files (to be explained later), and answers to the questions in this assignment. The
questions in this assignment are meant to be thought-provoking. They illustrate important aspects of the C language. If you experience problems, do not
hesitate to ask a tutor for help!
Students who do not wish to use gdb or students who use their own development package (Borland C, etc.) will need to follow the steps dictated in the
instructions and demonstrate identical functionality in the debugger of their choice (e.g., via screenshots). If you can't provide such documentation, you will
need to use gdb.
The code associated with this assignment is a short program whose purpose is to turn regular phone numbers into "words." For example, the Federal Express
customer service number is 1-800-GO-FED-EX, translated from 1-800-46-333-39. The provided program, when working properly, will provide all possible
"words" that have no more than a user-specified number of consonants. (Too many consonants may make the "word" unpronounceable.) Below is a transcript
of how the program should work, with user input appearing in boldface:
This program finds words that can be associated with phone numbers.
What is the maximum number of consonants you would like
the generated word to possess?
(note: 0's and 1's are considered consonants)
4
Please enter a 7 digit phone number with dashes removed
4460175
iio01pj iio01pk iio01pl iio01rj iio01rk iio01rl iio01sj
iio01sk iio01sl iio01pj iio01pk iio01pl iio01rj iio01rk
iio01rl iio01sj iio01sk iio01sl iio01pj iio01pk iio01pl
iio01rj iio01rk iio01rl iio01sj iio01sk iio01sl iio01pj
iio01pk iio01pl iio01rj iio01rk iio01rl iio01sj iio01sk
iio01sl iio01pj iio01pk iio01pl iio01rj iio01rk iio01rl
iio01sj iio01sk iio01sl iio01pj iio01pk iio01pl iio01rj
iio01rk iio01rl iio01sj iio01sk iio01sl iio01pj iio01pk
iio01pl iio01rj iio01rk iio01rl iio01sj iio01sk iio01sl
iio01pj iio01pk iio01pl iio01rj iio01rk iio01rl iio01sj
iio01sk iio01sl iio01pj iio01pk iio01pl iio01rj iio01rk
iio01rl iio01sj iio01sk iio01sl
Would you like to try another number? (Y/N)
n
Before continuing on with this assignment, make sure you have done all of the associated reading and understand how the code we've provided should work.
The program can be found in the file ~cs9c/lib/generate.c.
Assignment
The first step in the debugging process is the compilation of the program. In the process of compiling code, useful error messages are provided that identify
problematic parts of the code that are not syntactically correct. Very often, these mistakes are typos.
If you haven't done so already, copy the file into your own directory using the following command:
% cp ~cs9c/lib/generate.c . (don't forget the dot!)
To compile the program type:
% gcc generate.c
1
You should see something similar to the following (your output may not be exactly the same):
1/9/14 8:13 PM Program-Debugging
Page 2 of 8 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.debugging.html
generate.c: In function 'main':
generate.c:54: parse error before 'puts'
generate.c: In function 'print_if_good':
generate.c:210: warning: value computed is not used
generate.c: At top level:
generate.c:231: warning: return-type defaults to 'int'
generate.c:231: conflicting types for 'convert'
generate.c:9: previous declaration of 'convert'
generate.c: In function 'convert':
generate.c:236: warning: control reaches end of non-void function
The numbers after the filename refer to the numbers of lines that contain errors. "Parse errors" typically signify something that is syntactically incorrect.
"Warnings" are issued for code that the C compiler believes to be problematic but that is syntactically correct. Warnings will not prevent your code from
compiling, but they can tip you off to some rather serious problems.
1. Use the text editor of your choice, correct the errors. (Typing ctrl-C in Pico or esc-x line-number-mode in emacs tells you what line you're on.)
Make a note of what changes you made. You may need to make small changes and recompile to see if those errors are fixed. This may take several
iterations. It is okay not to fix all the warnings but all of the non-warning problems will need to be fixed.
If you reach this point:
generate.c: In function 'print_if_good':
generate.c:210: warning: value computed is not used
Your program has compiled successfully; Don't try to figure out what's wrong with this line yet. We'll figure it out eventually.
In order to record your debugging session, you will need to use the script command. The script command stores the text of your session in a file. Type the
following:
% script assignment2
Your prompt may change at this point (don't worry). Now all of your interaction with the prompt will be recorded in the file named assignment2.
Let's see if the program works. To run the compiled program type the following (words you type are in bold):
% a.out
This program finds words associated with phone numbers.
What is the maximum number of consonants you would like
the generated word to possess?
(note: 0's and 1's are considered consonants)
4
Please enter a 7 digit phone number with dashes removed
4460175
2. The program has one or more bugs. How does the output suggest something is wrong?
We will now use gdb to begin debugging. To start gdb debugging this program, type:
% gdb a.out
GDB is free software and you are welcome to distribute copies of it under
certain conditions; type "show copying" to see the conditions.
There is absolutely no warranty for GDB; type "show warranty" for
details.
GDB 4.16 (hppa1.1-hp-hpux9.05), Copyright 1996 Free Software Foundation,
Inc...
(gdb)
Before we begin running the program, we will need to set a breakpoint. A breakpoint is a programmer-specified point in the code where we would like the
program to "pause" at while the program is running. Why would we want to do this? Using a debugger, we may examine variables in this paused state which
will give us important information about whether or not the program is working correctly. Type:
(gdb) break main
Breakpoint 1 at 0x2330: file generate.c, line 42.
This will ask the program to stop at the first executed line of code of the main ( ) function. Variable declarations will be processed immediately. To run the
program, and have it stop at this point, type:
(gdb) run
Breakpoint 1, main ( ) at generate.c:42
43 goahead = 1;
Notice that the program has stopped right before it is about to execute a line of code. In this case, the line of code in question is line 43 (your output may
vary). To see this, let's find out what the value of goahead is. Type the following:
(gdb) print goahead
$1 = -1073785707
In the above case, the variable goahead is storing a garbage integer (your output will definitely vary here!). Remember, if you don't assign a variable an initial
1/9/14 8:13 PM Program-Debugging
Page 3 of 8 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.debugging.html
value, its contents will be unpredictable. Now type:
(gdb) next
44 while (goahead)
The next command executes the line of code that was stopped at, and then stops the program at the very next line of code. To make sure the assignment
goahead = 1 has actually taken place, we can again view the contents of goahead:
(gdb) print goahead
$2 = 1
Sometimes we may want to find out the value of a variable after each statement. gdb provides this functionality in its display command. Type:
(gdb) display goahead
1: goahead = 1
(gdb) next
puts ("This program finds words associated with phone numbers.\n\n");
1: goahead = 1
Continue executing the program line by line using the next command. Stop when you see the following:
57 gets (input);
1: goahead = 1
Type the following:
(gdb) display input
2: input = "38!(@#*(#*!(@#1"
(gdb) next
4
64 maxNumConsonant = input[0] - '0';
2: input = "4\000!(@#*(#*!(@#1"
1: goahead = 1
Notice that the contents of the string input has changed. Since strings are null-terminated, when gets reads a string, it copies the user's input into the array
passed into the function and places a null terminator (denoted by \000 in the display portion) into the array when it reads a carriage return.
3. Using the techniques you have learned so far, explain what gets copied into maxNumConsonant after the line above is executed. What gdb commands
did you use to find out what was copied into maxNumConsonant? Explain what input[0] - '0' does.
Continue executing the code line by line until the following is reached
2
:
71 generateSpellings (phone, maxNumConsonant);
generateSpellings is a defined function within this program. We may be interested in watching what happens within the generateSpellings function. If
we type next at this point, we will go to the next instruction instead of going inside the generateSpellings function. In order to go inside
generateSpellings, we can use the step command:
(gdb) step
generateSpellings (phone=0x7fffbda8 "4460175", maxNumConsonant=4) at
generate.c:128
128 char dial[10][4]={
Several things happen now. First, the variables that you painstakingly "displayed" one by one are no longer refreshed. The reason is because those variables
are not accessible from within the generateSpellings function. The line above shows the contents of the two variables passed into the function: phone and
maxNumConsonant. Your output may be somewhat different.
For your information, 0x7fffbda8 is the hexadecimal (base 16) equivalent for 2,147,466,664. gdb denotes memory addresses by the 0x prefix. As you can
see, the hexadecimal format is a more efficient way of representing large numbers.
4. What is the value stored in phone? (Hint: Everyone's answer will be different.) Why is phone represented by an address?
Continue using the next command until you see:
144 convert (phone, phone_int);

Let's step into this function as well:
(gdb) step
convert (phone=0x7fffbda8 "4460175", phone_int=0x7fffbd08) at gener-
ate.c:233
251 for (i = 0; i < 7; i++)
When stepping into a function, gdb does not display the contents of an integer array when it is passed in as an argument. This is unlike what it does with
character arrays. (Note the difference between phone and phone_int.) However, regardless of variable type, gdb will always show you what the value of that
variable is when it is passed into the function. If this doesn't make sense, then you didn't answer question 4 correctly.
In the next five lines is a for loop. It is often helpful to monitor a for loop's progress. Type the following:
1/9/14 8:13 PM Program-Debugging
Page 4 of 8 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.debugging.html
(gdb) display i
3: i = 74128
(gdb) display phone_int[0]
4: phone_int[0] = 268530816
(gdb) display phone_int[1]
5: phone_int[1] = 4199972
(gdb) display phone_int[2]
6: phone_int[2] = 8192
(gdb) display phone_int[3]
7: phone_int[3] = 0
(gdb) display phone_int[4]
8: phone_int[4] = 843604063
(gdb) display phone_int[5]
9: phone_int[5] = 0
(gdb) display phone_int[6]
10: phone_int[6] = 268436928
Again, because values have not been assigned to the array cells above, their contents are in fact completely arbitrary. Your output may differ somewhat.
Monitoring the for loop's progress generally means stepping through it via repeated step or next commands. In gdb, hitting return re-executes the most
recent command; this facility simplifies the process of monitoring a long stretch of code.
5. Use the techniques that you've learned thus far and determine whether or not the for loop in this function works. What evidence suggests so?
When you exit the function, you should see the following:
generateSpellings (phone=0x7fffbda8 "4460175", maxNumConsonant=4)
at generate.c:152
157 for (a = 0; a < 3; a++)
The statement above lets you know that you've returned to the calling function (in this case, generateSpellings).
6. Starting on the above line, a series of nested loops is encountered. How does each nested loop work? Make sure you step through the loop and
demonstrate that you've actually examined how the loop works.
Continue executing the code line by line until you reach
176 print_if_good(maxNumConsonant, word, &level);

7. What is the current value of word? Which gdb command did you use to find its value? Is its value correct?
8. In line 176, the address of the variable level is passed into print_if_good as opposed to the variable's contents. The comments explain that this is a
technique that allows the function to change the contents of a variable passed into a function. Explain how passing a pointer to a variable
accomplishes this.
Step into this function using the step command:
(gdb) step
print_if_good (maxNumConsonant=4, word=0x7fffbd48 "ggm01pj",
level=0x7fffbd50)
at generate.c:193
206 int numVowel = 0;
In the following code, there is a for loop that counts the number of vowels and an if statement that determines whether or not the generated word is printed.
We are interested in testing what happens when the if condition is true. Since we may not enter the condition every time, we could end up typing next many
times before we reach the statements within the if condition. One way to skip to the "interesting" part of the program is to execute the following commands:
(gdb) break 207
(gdb) continue
In the above gdb statements, we have asked the program to stop at line 207. Line 207 is the call to printf within the if statement. The continue statement
tells the program to run at full speed until the next breakpoint is reached-in this case, when we next execute line 207.
You should eventually see something similar to
Breakpoint 2, print_if_good (maxNumConsonant=4, word=0x7fffbd48
"iio01pj",
level=0x7fffbd50) at generate.c:207
207 printf ("%s ",word);
Print the word and go to the next line:
(gdb) next
210 *level++;
Now find out what the value of level and *level is (your output will vary):
(gdb) display level
1/9/14 8:13 PM Program-Debugging
Page 5 of 8 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.debugging.html
11: level = (int *) 0x7fffbd50
(gdb) display *level
12: *level = 0
The hexadecimal number 0x7fffbd50 is 2,147,466,576 in decimal. Let's find out what happens when we execute this line.
229 if ((*level)%7 == 0)
4: *level = 0
3: level = (int *) 0x7fffbd54
The value of level is now 0x7fffbd54 or in decimal, 2,147,466,580. *level is still 0. What result did we expect? It seems like we might have a problem
here.
9. Explain what the problem is in this section of code. Fix the problem in the code, and recompile the program. What happened to the warning?
The quit command exits gdb.
When you've recompiled the program, verify the rest of the program works as described. To end your script, type:
% exit
You will need to turn in your corrected version of generate.c, the script of your interaction with the debugger, and your answers to the boxed questions in
this assignment.
Checklist
A satisfactory grade on this assignment requires the following:
Corrected version of generate.c
Script of debugger interaction
Answers to questions 1 through 9
HY: 8/98
Buggy program
#include <stdio.h>
#include <string.h>
/****************************************************************
Function declarations.
*************************************************************** */
void generateSpellings (char [], int);
void convert (char phone[], int* phone_int);
void print_if_good (int, char[], int[]);
int isvowel (char);
/****************************************************************
main( )
input
Character array that is used to store user input.
Its size is greater than two characters in order to
accommodate responses such as yes/no and possibly
other unpredictable user responses. (See a tutor for
an explanation.)
phone
Character array used to store the actual phone number
entered by the user. Space is allocated for seven
digits and the corresponding carriage return.
maxNumConsonant
User-entered value that filters out those
numbers with too many consonants.
goahead
true/false flag that determines whether or not
the user wants to test another number.
*************************************************************** */
int main ( ) {
int maxNumConsonant;
int goahead;
char input[8];
char phone[8];

goahead = 1;
while (goahead) {
/* This part of the code gathers user data. The use of puts and gets is illustrated here.
puts sends its char array to standard output followed by a carriage return. gets puts
everything in the standard input up to the carriage return into a character array. In place
of the carriage return, puts has a '\0' to signify the end of the string. */
puts ("This program finds words associated with phone numbers.\n\n");
puts ("phone numbers\n\n")
1/9/14 8:13 PM Program-Debugging
Page 6 of 8 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.debugging.html
puts("What is the maximum number of consonants you would like");
puts("the generated word to possess?");
puts ("(note: 0's and 1's are considered consonants)");
gets (input);

/* Each digit read in as a character needs to be converted to a number for comparison pur-
poses later. The difference between the ASCII value of the user input and the ASCII value
of '0' will return the appropriate numeric value for the character. */
maxNumConsonant = input[0] - '0';
puts ("Please enter a 7-digit phone number with dashes removed");
gets (phone);

/* The generateSpellings function does most of the work. */
generateSpellings (phone, maxNumConsonant);
putchar ('\n');
putchar ('\n');
puts ("Would you like to try another number? (Y/N)");
gets (input);
if ((input[0] == 'Y') || (input[0] == 'y')) {
goahead = 1;
} else {
goahead = 0;
}
}
return 0;
}
/*****************************************************************
generateSpellings (char*, int)
phone_int
The characters '1', '2', '3', ... are converted to
1, 2, 3, ... and stored appropriately in this
numeric representation of the user's phone number.
level
This variable is used to make the printouts nice.
It is passed using the "address of" operator, as described in House
in section 5.2.1. Passing a variable using the "address of" operator
in this way is a technique that allows a function to
change its contents in such a way that the changes
are recognized in the calling program.
Note that level should really be a local variable in
generateSpellings; it is used as a parameter here for
illustrative purposes.
a-g
Index variables used to keep track of for loops.
word
A candidate "word" that is then passed on to
print_if_good, which prints the word if it meets
the minimum requirements for consonants. The
representation is again an array of characters
terminated by a NULL ('\0').
dial
A two-dimensional array. For each dial [i][j], i represents
the actual number on the key pad (a value between 1 and 10)
and j indicates a choice of letter that the key pad could represent.
So, for example, dial[2][3] would represent the
third letter on button #2 of the keypad, namely the letter "c".
Similarly, dial[2][2] == 'b', dial [3][3] = 'f', etc.
Confused? Pick up your phone and take a look!
Some letters aren't mapped the way they should be.
Note that the letters "q" and "z" have been removed.
The numbers 0 and 1 have no associated letters and so
the program simply returns a "1" or a "0" in those
circumstances.
*************************************************************** */
void generateSpellings (char* phone, int maxNumConsonant) {
int phone_int[7];
int a, b, c, d, e, f, g;
char word[8];
int level;
char* dial[10] = {"000", "111", "abc", "def", "ghi", "jkl",
"mno", "prs", "tuv", "wxy"};
/* Each ASCII character stored in phone is converted to its appropriate number. */
level = 0;
convert (phone, phone_int);
/* The following for loop works as follows: for each of the seven digits in the phone number, we
generate all the different possible letters each letter can take on by considering each digit in
turn until all values are exhausted. */
for (a = 0; a < 3; a++) {
for (b = 0; b < 3; b++) {
for (c = 0; c < 3; c++) {
for (d = 0; d < 3; d++) {
for (e = 0; e < 3; e++) {
for (f = 0; f < 3; f++) {
for (g = 0; g < 3; g++) {
/* The candidate word is built here. Starting with the first letter of
the word we assign a candidate translation dial[][a] based on
1/9/14 8:13 PM Program-Debugging
Page 7 of 8 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.debugging.html
the original number's value. */
word[0] = dial[phone_int[0]][a];
word[1] = dial[phone_int[1]][b];
word[2] = dial[phone_int[2]][c];
word[3] = dial[phone_int[3]][d];
word[4] = dial[phone_int[4]][e];
word[5] = dial[phone_int[5]][f];
word[6] = dial[phone_int[6]][g];
word[7] = '\0';
/* print_if_good prints the word if it meets the minimum
requirements. */
print_if_good (maxNumConsonant, word, &level)
}
}
}
}
}
}
}
}
/* This function prints the word if it has maxNumConsonant or fewer consonants. */
void print_if_good (int maxNumConsonant, char* word, int *level) {
int i;
int numVowel = 0;
/* This loop counts the number of vowels. */
for (i = 0; i < 7; i++) {
if (isvowel(word[i])) {
numVowel++;
}
}

/* This loop prints the word if there is maxNumConsonant or fewer consonants. */
if ((7 - numVowel) <= maxNumConsonant) {
printf ("%s ",word);
/* Every time we print a word, we add 1 to the value of level. */
*level++;
/* Every seventh word we print, we add a carriage return to make the format nice. */
if ((*level)%7 == 0) {
putchar ('\n');
}
}
}
/* This function checks to see if the letter in question is "a", "e", "i", "o", or "u". */
int isvowel (char x) {
return ((x == 'a') || (x == 'e') || (x == 'i') || (x == 'o') || (x == 'u'));
}
/* This function converts the character array into numbers and places its contents into
the array phone_int. */
convert (char* phone, int* phone_int) {
int i;
for (i = 0; i < 7; i++) {
phone_int[i] = phone[i] - '0';
}
}
1
The actual command is gcc -g -Wall generate.c but we've set up the account so that you don't need to worry about the command line options
following gcc when compiling from the shell. The -g option links the source code to the executable and the -Wall option turns on warnings. In
emacs you can compile your program without exiting the editor. Type esc-x compile and then hit return. Delete the contents of the command line
and replace that with gcc -g -Wall generate.c.
2
You will be prompted to enter a phone number with dashes removed somewhere in the process. After the program has read the input phone number,
you may want to verify that the appropriate information was read.
1/9/14 8:13 PM Program-Debugging
Page 8 of 8 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.debugging.html
1/9/14 8:14 PM Quiz-Functions and argument pointers
Page 1 of 2 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.functs.arg.ptrs.html
Quiz Functions and
argument pointers
This quiz covers the definition and use of functions. Details that are tested here include the use of
pointers to allow functions (including scanf) to change values in code that calls them and the use
of the strcpy and strcmp functions accessible through <string.h>.
Readings
House, chapter 7, sections 5.1, 5.2, 5.3, 12.1 and 12.2, and material on <string.h> in chapters 3
and 6.
Kernighan and Ritchie, chapters 1 through 4 except sections 1.10, 3.8, 4.3, 4.5, 4.6, 4.7, 4.10,
4.11.2, and 4.11.3. You will not be tested on material on arrays in chapters 2 through 4.
Suggested exercises
House, "short answer" self-test exercises and test questions in chapters 5 and 7. You may also be
asked to write small program segments.
Sample quiz
1. What is the output of the following program segment?
c = 'a';
putchar (c);
putchar (F(c));
putchar (c);
Assume that the function F has been defined as follows:
char F (char c) {
c = 'f';
return (c);
}
2. Modify the code from exercise 1 so that, on return from the F function, the variable c in
the calling code contains the character 'f'.
3. Write a function AllDone that, given a string as argument, returns a true value if the string
is "exit" and returns false otherwise.
4. Write a function GetWordAndValue that prompts the user for a string and an integer, reads
the values, and returns both to the calling program. Assume that the caller has already
provided space in memory for all the characters of the word.
5. Write a main program that calls GetWordAndValue and echoes the values returned.
1/9/14 8:14 PM Quiz-Functions and argument pointers
Page 2 of 2 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.functs.arg.ptrs.html
1/9/14 8:16 PM Program-Abstract data types with trees
Page 1 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
Program Abstract data types
with trees
Most of the significant breakthroughs in computing science have been achieved through a process of
representation, that is to say, changing one's way of perceiving a problem so that it can be solved
more easily. Structures such as lists, trees, tables and so forth have meaning to us as problem
solvers, but do not have direct existence in the computer. The C struct and typedef language
constructs allow programmers to represent more abstract structures in terms of the simple data
objects built into the language.
C allows the use of the programmer to isolate the details of the implementation of a data type in a
single file or group of files. By using access functions and header files it is possible for one series of
functions to use a data structure without ever dealing with the actual language primitives that define
the data structure. This use of an abstract data type is good software engineering; it allows one to
implement and modify the implementation of the data structure with minimal change to the rest of
the program.
Careless C programmers often write code with "memory leaks", that is, instances where storage is
requested via malloc and never freed. A process that runs a long time with a memory leak, for
example, a part of the operating system or a process that runs in the background monitoring user
interaction, will eventually leave no room for other programs. This assignment gives you some
practice tracking down these problems.
Readings
House, chapters 10, 11, 14, and 15; sections 12.4, 13.2, and 13.3. (It will also be useful to review
section 13.1.) Chapter 15 is especially important as motivation for the way your solution program
will be structured.
Kernighan and Ritchie, section 4.11.3; chapter 6 except sections 6.8 ("Unions") and 6.9 ("Bit-
fields"); the entry for fopen in Appendix B.
The sections "Abstract data types in C" and "Basic compilation control using make" later in this
document.
Related quizzes
Structures
Programming assignment 4
The "Animal" game, revisited
Goals
This assignment illustrates how to implement an abstract data type in C; it also gives you
1/9/14 8:16 PM Program-Abstract data types with trees
Page 2 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
practice with structures and linked structures, and with eliminating memory leaks.
Problem
Write and test two modules to represent and process the animal data tree. One module will represent
the tree in conventional C fashion as an array of character pointers, declared as follows:
struct treeStruct {
char *nodes[MAXNUMQS];
};

struct positionStruct {
int nodeIndex;
};
The other will represent it as an explicitly linked tree, declared as follows.
struct treeStruct {
char *string;
struct treeStruct *left, *right;
};

struct positionStruct {
struct treeStruct* node;
};
In either case, TreeType and PositionType would be defined as described in House section 15.2:
typedef struct treeStruct *TreeType;
typedef struct positionStruct *PositionType;
Each module will be used with the code in Appendix 1 (essentially the code you were given in
assignment 3) to complete a program to play the animal game.
You are not to change the main program. Instead, you are to create three files to accompany it:
animal.h, animal1.c, and animal2.c.
animal.h will contain prototypes (function headers) for the twelve functions that complete the
program and typedefs for TreeType and PositionType. It will not contain definitions for
struct treeStruct and struct positionStruct, since these depend on what module you
are using. (ANSI C allows the definition of a pointer type without the immediate definition of
the type pointed to. See the explanation of "incomplete type" in chapter 15 of House and
section A8.3 of Kernighan and Ritchie.) Finally, it will contain an #ifndef surrounding the
lines just described, that prevents compiler errors involving multiple definitions.
animal1.c will contain code for the twelve functions and the definitions for the structures for
one of the implementations. The line #include "animal.h" will appear in the file before the
functions and struct definitions.
animal2.c will contain code for the twelve functions and the definitions for the structures for
the other implementation. It will also contain the line #include "animal.h" before its
functions and struct definitions.
In addition, at least one of your two implementations should initialize the tree from a file whose
1/9/14 8:16 PM Program-Abstract data types with trees
Page 3 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
name is specified as a command line argument. Your program should check the result of the fopen
function to ensure that a legal file name was specified. When your program exits, it should save the
new tree to that file, after again checking to make sure the file is writable. (Chapter 10 of House and
Appendix B of Kernighan and Ritchie describes functions that will allow you to make a backup of
the tree file before you write your new file, if you so desire). When you bring your program to be
graded, accompany it by documentation of the file format.
Any storage requested using malloc or calloc and not required for the representation of the animal
data tree should be freed using the free function. Tutors will require you to verify that each use of
malloc or calloc other than those whose storage is a component of the animal tree is accompanied
by a call to free.
As in programming assignment 3, test each module on guesses that exercise "yes" branches as well
as "no" branches, and on games that result in successful guesses as well as unsuccessful guesses.
Provide evidence that your functions work correctly in isolation as well as in combination.
Miscellaneous information
The main program's source file p4.c is online in the directory ~cs9c/lib for your reference.
A key requirement of this assignment is the interchangeability of the modules. The tradeoff for this
design feature is more complex code: the array implementation forces an extra level of indirection to
access a node, and redundant information is passed through parameters in the explicitly linked tree
implementation. (Some compilers will generate warnings about the redundancy.) The extra
complexity, we hope, will not be excessive, and will provide you with more experience working
with C pointers.
If you're using a UNIX account for this class, we suggest that you use the make program to compile
and load your completed program. Do this by creating a file called makefilewe've supplied such
a file in ~cs9c/lib/p4.makefileand by typing the command make -e animal1 or make -
e animal2 depending on which of your modules you wish to test. The document "Basic
Compilation Control with Make" in this document describes the make program; the ambitious among
you may wish to change the "make file" to automate your testing as well as your compiling and
loading. The -e option for make gives the LIB variable in the "make file" the value of the LIB
variable from the environment.
The following recursive algorithm may be used to initialize an explicitly linked tree from a file:
read a line;
if there was no line to read (the end of the file has been reached)
return NULL;
if the line is empty
return NULL;
otherwise
allocate a tree node;
call the algorithm recursively to get a pointer to its left child;
if the left child isn't NULL
call the algorithm recursively to get a pointer to the right child;
return a pointer to the tree node.
1/9/14 8:16 PM Program-Abstract data types with trees
Page 4 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
Checklist
A satisfactory grade on this assignment requires the following:
Correct behavior in guessing and adding nodes to the animal tree.
Freeing of memory not used in representation of the animal tree.
Sufficient test games.
File input in at least one implementation, using an error-checked file name supplied on the command
line, with accompanying documentation of the file format.
File output in at least one implementation, using a file name supplied on the command line (creating
a backup of the file before writing is optional).
Correct setup of .h and .c files.
Good style and layout.
No function more than 24 lines long.
Reasonable names for functions, variables, and parameters.
Appropriate use of auxiliary functions.
Evidence that subprograms were tested in isolation.
No changes to main program.
MJC, DE: 8/99
Appendix 1: Main program for animal
/* DO NOT MODIFY THIS FILE */
#define FALSE 0
#define TRUE !FALSE
#define MAXSTR 80
#include <stdio.h>
#include "animal.h"
/*
* Play the "animal" game, in which the program attempts to guess an animal
* that the user is thinking of by asking yes or no questions. Eventually,
* the program either will guess the user's animal or run out of questions
* to ask. In the latter case, the program will ask the user to provide a
* yes-or-no question that would distinguish between the user's animal and
* the program's best guess.
* The data structure of questions and guesses is essentially a binary tree,
* with each internal node having a "yes" branch and a "no" branch. Leaves
* of the tree represent animals to be guessed by the program. If the program
* fails to guess the user's animal, it replaces one of the leaves of the tree
* by a node containing the new question, whose children are the program's
* best guess and the animal provided by the user.
* The structure of the program is simple. It initializes the question/guess
* data structure, then plays games as long as the user is interested. In each
* game, the program starts at the top of the tree (the root) and progresses
* toward the bottom (the leaves) depending on the user's responses. Once it
* reaches a leaf, it either has won or lost, and handles the situation as
* described above.
*/
int main (int argc, char *argv[]) {
char *treefile = NULL;
1/9/14 8:16 PM Program-Abstract data types with trees
Page 5 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
TreeType tree;
PositionType pos;
char *newQuestion, *newAnswer;
if (argc > 1) {
treefile = argv[1];
}
tree = InitTree (treefile);
printf("%s", "Think of an animal. I will try to guess what is.\n"
"Please answer my questions with yes or no.\n");
while (TRUE) {
pos = Top (tree);
while (!IsLeaf (tree, pos)) {
pos = Answer (Question (tree, pos))?
YesNode (tree, pos): NoNode (tree, pos);
}
if (Answer (Guess (tree, pos))) {
printf ("I got it right!\n");
} else {
GetNewInfo (tree, pos, &newAnswer, &newQuestion);
ReplaceNode (tree, pos, newAnswer, newQuestion);
}
if (!Answer ("Want to play again? ")) {
WriteTree(tree, treefile);
return 0;
}
}
}
Appendix 2: Functions to be implemented in each module
WriteTree is a new function you have to write.
/*
* Writes a tree to the given file (if specified).
*/
void WriteTree(TreeType tree, char *file);
Descriptions of these functions appear in programming assignment 3.
/*
* Return an animal tree (from file, if specified).
*/
TreeType InitTree (char *file);
void PrintTree (TreeType tree);
PositionType Top (TreeType tree);
boolean IsLeaf (TreeType tree, PositionType pos);
boolean Answer (char *question);
char *Question (TreeType tree, PositionType pos);
char *Guess (TreeType tree, PositionType pos);
PositionType YesNode (TreeType tree, PositionType pos);
PositionType NoNode (TreeType tree, PositionType pos);
void ReplaceNode (TreeType tree, PositionType pos, char *newA, char *newQ);
void GetNewInfo (TreeType tree, PositionType pos, char **newA, char **newQ);
1/9/14 8:16 PM Program-Abstract data types with trees
Page 6 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
1/9/14 8:26 PM Quiz-Arrays, structures, and files
Page 1 of 2 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.arrays.structs.files.html
Quiz Arrays, structures, and
files
This quiz covers typical uses of C arrays (one- and two-dimensional), structures, and files.
Included are questions on the typedef declaration and on the predefined file pointers stdin,
stdout, and stderr.
Readings
House, chapters 9 through 11.
Kernighan and Ritchie, material on arrays in chapters 1 through 4, section 5.7, 6.1 through 6.3,
6.7, and 7.1 through 7.7.
Suggested exercises
House, section 5.7 #2 and #7; all "short answer" self-test exercises and test questions in chapters
9 through 11.
Sample quiz
1. Fill in the blanks in the program below so it prints the contents of the file whose name is
provided by the user.
#include <stdio.h>
int main ( ) {
char fileName[32];
char c;
FILE *inFile;
printf ("File name? ");
gets (fileName);
_________________________ ;
if ( ____________________ ) {
fprintf ( _____________ , "File doesn't exist!\n");
exit (1);
};
while ( ____________________ ) { /* get a char if not done */
fprintf ( _______________ ); /* print it */
}
return 0;
}
2. Define a struct to represent dates. The struct members should be a string representing
the month, an integer representing the date in the month, and another integer representing
the year. Then define the type Date to be synonymous with the struct definition, and
define an array dateList of five dates.
3. Fill in the blank in the code below so that it moves each element of the values array to the
1/9/14 8:26 PM Quiz-Arrays, structures, and files
Page 2 of 2 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.arrays.structs.files.html
immediately subsequent position in the array. The loop should discard the last value in the
array. Thus if the array contained the values 1, 2, 3, 4, and 5 before the loop, it should
contain the values 1, 1, 2, 3, and 4 after the loop.
int values[5];
...
for ( ____________________ ) {
values[k] = values[k-1];
}
4. Modify the definition of the values array in exercise 3 so that it also initializes the array to
contain the values 1, 2, 3, 4, 5.
5. Write a function HasZeroDiagonal that, given a 5-by-5 integer array, returns 1 if all the
elements on the main array diagonal are zero and returns 0 otherwise.
1/9/14 8:15 PM Quiz-General use of pointers
Page 1 of 2 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.general.use.ptrs.html
Quiz General use of pointers
This quiz tests your understanding of the definition and use of C pointers. Questions for this quiz
ask about the meaning of the *, &, and ** prefix operators; about the relation between pointer
and array use; about the distinction between pointer and thing-pointed-to; and about the
declaration of pointer arrays. You will also be expected to be able to draw a diagram of a C
pointer object, and to determine the proper declaration for an object shown in a diagram. You
should be able to detect type clashes that would probably lead to obscure bugs at run time.
Finally, you should be aware of how to use the malloc and calloc functions and of when they're
necessary.
Readings
House, section 6.5, chapter 9, sections 12.1-12.3, 13.1, 13.3, and appendix D13.
Kernighan and Ritchie, sections 5.1 through 5.5, 7.8, and B3.
Suggested exercises
House, section 12.6 #2 and #3; section 12.7 #3; section 13.7 #1-4 and #6; section 13.8 #1-3. You
will also be expected to write short program segments.
Sample quiz
1. (Exercise 5.3 in K&R) Rewrite the strcat function given below, which uses array
indexing, to use pointers instead.
void strcat (char s[], char t[]) {
int i, j;
i = j = 0;
while (s[i] != '\0') {
i++;
}
while ((s[i++] = t[j++]) != '\0') {
}
}
2. Consider the following function, intended to return a string typed by the user to the caller.
char* WordInput ( ) {
char word[20];
printf ("Type a word: ");
scanf ("%s", word);
return word;
}
What's wrong with the function? Does replacing its second line by
1/9/14 8:15 PM Quiz-General use of pointers
Page 2 of 2 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.general.use.ptrs.html
char* word;
fix the problem?
3. What is the meaning of the following declaration?
char* a, b;
4. Which of the following would cause compile-time or run-time problems? Please explain.
Also give the type of the right-hand side of each assignment statement, and draw a
diagram for each legal assignment to the pointer variable px.
float x, *px, a[5];
x = *px; /* 1 */
*px = x; /* 2 */
px = &x; /* 3 */
&x = px; /* 4 */
&(x+1) = x; /* 5 */
&(x)+1 = x; /* 6 */
*(&(x+1)) = x; /* 7 */
*(&(x)+1) = x; /* 8 */
x = a; /* 9 */
x = a[0]; /* 10 */
x = *(a[1]); /* 11 */
x = (*a)[2]; /* 12 */
x = a[3+1]; /* 13 */
x = a[3]+1; /* 14 */
x = &((a[3])+1); /* 15 */
x = &(a[3])+1; /* 16 */
x = *(&(a[3])+1); /* 17 */
px = a; /* 18 */
px = a[0]; /* 19 */
px = &(a[4]); /* 20 */
1/9/14 8:16 PM Program-Abstract data types with trees
Page 1 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
Program Abstract data types
with trees
Most of the significant breakthroughs in computing science have been achieved through a process of
representation, that is to say, changing one's way of perceiving a problem so that it can be solved
more easily. Structures such as lists, trees, tables and so forth have meaning to us as problem
solvers, but do not have direct existence in the computer. The C struct and typedef language
constructs allow programmers to represent more abstract structures in terms of the simple data
objects built into the language.
C allows the use of the programmer to isolate the details of the implementation of a data type in a
single file or group of files. By using access functions and header files it is possible for one series of
functions to use a data structure without ever dealing with the actual language primitives that define
the data structure. This use of an abstract data type is good software engineering; it allows one to
implement and modify the implementation of the data structure with minimal change to the rest of
the program.
Careless C programmers often write code with "memory leaks", that is, instances where storage is
requested via malloc and never freed. A process that runs a long time with a memory leak, for
example, a part of the operating system or a process that runs in the background monitoring user
interaction, will eventually leave no room for other programs. This assignment gives you some
practice tracking down these problems.
Readings
House, chapters 10, 11, 14, and 15; sections 12.4, 13.2, and 13.3. (It will also be useful to review
section 13.1.) Chapter 15 is especially important as motivation for the way your solution program
will be structured.
Kernighan and Ritchie, section 4.11.3; chapter 6 except sections 6.8 ("Unions") and 6.9 ("Bit-
fields"); the entry for fopen in Appendix B.
The sections "Abstract data types in C" and "Basic compilation control using make" later in this
document.
Related quizzes
Structures
Programming assignment 4
The "Animal" game, revisited
Goals
This assignment illustrates how to implement an abstract data type in C; it also gives you
1/9/14 8:16 PM Program-Abstract data types with trees
Page 2 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
practice with structures and linked structures, and with eliminating memory leaks.
Problem
Write and test two modules to represent and process the animal data tree. One module will represent
the tree in conventional C fashion as an array of character pointers, declared as follows:
struct treeStruct {
char *nodes[MAXNUMQS];
};

struct positionStruct {
int nodeIndex;
};
The other will represent it as an explicitly linked tree, declared as follows.
struct treeStruct {
char *string;
struct treeStruct *left, *right;
};

struct positionStruct {
struct treeStruct* node;
};
In either case, TreeType and PositionType would be defined as described in House section 15.2:
typedef struct treeStruct *TreeType;
typedef struct positionStruct *PositionType;
Each module will be used with the code in Appendix 1 (essentially the code you were given in
assignment 3) to complete a program to play the animal game.
You are not to change the main program. Instead, you are to create three files to accompany it:
animal.h, animal1.c, and animal2.c.
animal.h will contain prototypes (function headers) for the twelve functions that complete the
program and typedefs for TreeType and PositionType. It will not contain definitions for
struct treeStruct and struct positionStruct, since these depend on what module you
are using. (ANSI C allows the definition of a pointer type without the immediate definition of
the type pointed to. See the explanation of "incomplete type" in chapter 15 of House and
section A8.3 of Kernighan and Ritchie.) Finally, it will contain an #ifndef surrounding the
lines just described, that prevents compiler errors involving multiple definitions.
animal1.c will contain code for the twelve functions and the definitions for the structures for
one of the implementations. The line #include "animal.h" will appear in the file before the
functions and struct definitions.
animal2.c will contain code for the twelve functions and the definitions for the structures for
the other implementation. It will also contain the line #include "animal.h" before its
functions and struct definitions.
In addition, at least one of your two implementations should initialize the tree from a file whose
1/9/14 8:16 PM Program-Abstract data types with trees
Page 3 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
name is specified as a command line argument. Your program should check the result of the fopen
function to ensure that a legal file name was specified. When your program exits, it should save the
new tree to that file, after again checking to make sure the file is writable. (Chapter 10 of House and
Appendix B of Kernighan and Ritchie describes functions that will allow you to make a backup of
the tree file before you write your new file, if you so desire). When you bring your program to be
graded, accompany it by documentation of the file format.
Any storage requested using malloc or calloc and not required for the representation of the animal
data tree should be freed using the free function. Tutors will require you to verify that each use of
malloc or calloc other than those whose storage is a component of the animal tree is accompanied
by a call to free.
As in programming assignment 3, test each module on guesses that exercise "yes" branches as well
as "no" branches, and on games that result in successful guesses as well as unsuccessful guesses.
Provide evidence that your functions work correctly in isolation as well as in combination.
Miscellaneous information
The main program's source file p4.c is online in the directory ~cs9c/lib for your reference.
A key requirement of this assignment is the interchangeability of the modules. The tradeoff for this
design feature is more complex code: the array implementation forces an extra level of indirection to
access a node, and redundant information is passed through parameters in the explicitly linked tree
implementation. (Some compilers will generate warnings about the redundancy.) The extra
complexity, we hope, will not be excessive, and will provide you with more experience working
with C pointers.
If you're using a UNIX account for this class, we suggest that you use the make program to compile
and load your completed program. Do this by creating a file called makefilewe've supplied such
a file in ~cs9c/lib/p4.makefileand by typing the command make -e animal1 or make -
e animal2 depending on which of your modules you wish to test. The document "Basic
Compilation Control with Make" in this document describes the make program; the ambitious among
you may wish to change the "make file" to automate your testing as well as your compiling and
loading. The -e option for make gives the LIB variable in the "make file" the value of the LIB
variable from the environment.
The following recursive algorithm may be used to initialize an explicitly linked tree from a file:
read a line;
if there was no line to read (the end of the file has been reached)
return NULL;
if the line is empty
return NULL;
otherwise
allocate a tree node;
call the algorithm recursively to get a pointer to its left child;
if the left child isn't NULL
call the algorithm recursively to get a pointer to the right child;
return a pointer to the tree node.
1/9/14 8:16 PM Program-Abstract data types with trees
Page 4 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
Checklist
A satisfactory grade on this assignment requires the following:
Correct behavior in guessing and adding nodes to the animal tree.
Freeing of memory not used in representation of the animal tree.
Sufficient test games.
File input in at least one implementation, using an error-checked file name supplied on the command
line, with accompanying documentation of the file format.
File output in at least one implementation, using a file name supplied on the command line (creating
a backup of the file before writing is optional).
Correct setup of .h and .c files.
Good style and layout.
No function more than 24 lines long.
Reasonable names for functions, variables, and parameters.
Appropriate use of auxiliary functions.
Evidence that subprograms were tested in isolation.
No changes to main program.
MJC, DE: 8/99
Appendix 1: Main program for animal
/* DO NOT MODIFY THIS FILE */
#define FALSE 0
#define TRUE !FALSE
#define MAXSTR 80
#include <stdio.h>
#include "animal.h"
/*
* Play the "animal" game, in which the program attempts to guess an animal
* that the user is thinking of by asking yes or no questions. Eventually,
* the program either will guess the user's animal or run out of questions
* to ask. In the latter case, the program will ask the user to provide a
* yes-or-no question that would distinguish between the user's animal and
* the program's best guess.
* The data structure of questions and guesses is essentially a binary tree,
* with each internal node having a "yes" branch and a "no" branch. Leaves
* of the tree represent animals to be guessed by the program. If the program
* fails to guess the user's animal, it replaces one of the leaves of the tree
* by a node containing the new question, whose children are the program's
* best guess and the animal provided by the user.
* The structure of the program is simple. It initializes the question/guess
* data structure, then plays games as long as the user is interested. In each
* game, the program starts at the top of the tree (the root) and progresses
* toward the bottom (the leaves) depending on the user's responses. Once it
* reaches a leaf, it either has won or lost, and handles the situation as
* described above.
*/
int main (int argc, char *argv[]) {
char *treefile = NULL;
1/9/14 8:16 PM Program-Abstract data types with trees
Page 5 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
TreeType tree;
PositionType pos;
char *newQuestion, *newAnswer;
if (argc > 1) {
treefile = argv[1];
}
tree = InitTree (treefile);
printf("%s", "Think of an animal. I will try to guess what is.\n"
"Please answer my questions with yes or no.\n");
while (TRUE) {
pos = Top (tree);
while (!IsLeaf (tree, pos)) {
pos = Answer (Question (tree, pos))?
YesNode (tree, pos): NoNode (tree, pos);
}
if (Answer (Guess (tree, pos))) {
printf ("I got it right!\n");
} else {
GetNewInfo (tree, pos, &newAnswer, &newQuestion);
ReplaceNode (tree, pos, newAnswer, newQuestion);
}
if (!Answer ("Want to play again? ")) {
WriteTree(tree, treefile);
return 0;
}
}
}
Appendix 2: Functions to be implemented in each module
WriteTree is a new function you have to write.
/*
* Writes a tree to the given file (if specified).
*/
void WriteTree(TreeType tree, char *file);
Descriptions of these functions appear in programming assignment 3.
/*
* Return an animal tree (from file, if specified).
*/
TreeType InitTree (char *file);
void PrintTree (TreeType tree);
PositionType Top (TreeType tree);
boolean IsLeaf (TreeType tree, PositionType pos);
boolean Answer (char *question);
char *Question (TreeType tree, PositionType pos);
char *Guess (TreeType tree, PositionType pos);
PositionType YesNode (TreeType tree, PositionType pos);
PositionType NoNode (TreeType tree, PositionType pos);
void ReplaceNode (TreeType tree, PositionType pos, char *newA, char *newQ);
void GetNewInfo (TreeType tree, PositionType pos, char **newA, char **newQ);
1/9/14 8:16 PM Program-Abstract data types with trees
Page 6 of 6 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/p.ADTs.with.trees.html
1/9/14 8:16 PM Quiz-Linked structures
Page 1 of 2 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.linked.structs.html
Quiz Linked structures
This quiz tests your understanding of how linked structures are created and used. It also includes
questions on more advanced uses of pointers. Finally, you are expected to know about argv and
argc, which store information from the command line
Readings
House, sections 12.4 and 13.2-13.5.
Kernighan and Ritchie, 5.6, 5.8 through 5.12, 6.4, and 6.5.
Suggested exercises
House, "short answer" self-test exercises and test questions in chapters 12 and 13.
Sample quiz
1. What's the difference between the use of "." and the use of "->" in referring to a field of a
structure?
2. Declare a type named ListPtrType that's a pointer to a struct, each instance of which
contains an integer info member and a next member that's a pointer to an instance of the
struct type.
3. Write a function that returns a pointer to a newly-created node of the structure type you
just declared. Use sizeof and calloc to allocate the space for the new node.
4. Given the following declarations
struct tnode {
char *word;
struct tnode *left, *right;
};

typedef struct tnode TREENODE, *TREEPTR;
TREEPTR tree;
TREENODE node;
indicate which of the following are legal expressions; for legal expressions,
also indicate the type of the expression.
a. node->word[2]
b. node.word[2]
c. tree->left->word
d. *(tree->left)
e. *tree->left
f. tree->*left
5. What does *p++ mean?
1/9/14 8:16 PM Quiz-Linked structures
Page 2 of 2 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/q.linked.structs.html
6. Page 115 of K&R contains the following program to print the argument list.
int main (int argc, char *argv[]) {
while (--argc > 0) {
printf ("%s%s", *++argv, (argc > 1) ? " " : "");
}
printf ("\n");
return 0;
}
Modify this program to print the arguments on separate lines, and to omit duplicate
arguments from the argument list. If, for instance, the program is run with the
command line
a.out a b a c
the output should be
a
b
c
1/9/14 8:16 PM C Style Examples
Page 1 of 1 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/C.style.examples.html
C Style Examples
by P.N. Hilfinger
/* TITLES GO HERE */

/* Comments on variables may go here */
int x; /* or here */
/* Format 1: Comments describing a function that go before it may be */
/* formatted like this. This same format works for variables and general */
/* commentary about an entire program or section of a program. */
/* Format 2: Here is another possible format for extended comments
at the front of a source file or before function or variable declarations. */

/*
** Format 3: Here is still another possible format. Some find that comments
** stand out better in this format than in formats 1 or 2.
** Also it is possible to access all the comments via the grep command;
** format 1 allows this too, while format 2 doesn't.
*/
int F (double a[ ], double b[ ], double c[ ], int n)
/* Comments describing a function that go after its header */
/* are indented like this. */
{
if (n < 0) {
fprintf (stderr, "Erroneous input to F: %d.\n", n);
exit (1);
} else if (n == 0) { /* note that single statements */
return 0; /* should be bracketed too for safety */
} else {
int i;
for (i=0; i<n; i++) {
/* code is indented here */
}
}
switch (...) {
case 1:
x = n;
break;
case 2: {
int local_variable;
...
}
default: ...
}
}
1/9/14 8:17 PM Abstract data types in C
Page 1 of 3 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/ADTs.in.C.html
Abstract data types in C
What's an abstract data type?
You're well acquainted with data types by now, like integers, arrays, and so on. To access the
data, you've used operations defined in the programming language for the data type, for instance
by accessing array elements by using the square bracket notation, or by accessing scalar values
merely by using the name of the corresponding variables.
This approach doesn't always work on large programs in the real world, because these programs
evolve as a result of new requirements or constraints. A modification to a program commonly
requires a change in one or more of its data structures. For instance, a new field might be added
to a personnel record to keep track of more information about each individual; an array might be
replaced by a linked structure to improve the program's efficiency; or a bit field might be
changed in the process of moving the program to another computer. You don't want such a
change to require rewriting every procedure that uses the changed structure. Thus, it is useful to
separate the use of a data structure from the details of its implementation. This is the principle
underlying the use of abstract data types.
Here are some examples.
stack: operations are "push an item onto the stack", "pop an item from the stack", "ask if
the stack is empty"; implementation may be as array or linked list or whatever.
queue: operations are "add to the end of the queue", "delete from the beginning of the
queue", "ask if the queue is empty"; implementation may be as array or linked list or heap.
search structure: operations are "insert an item", "ask if an item is in the structure", and
"delete an item"; implementation may be as array, linked list, tree, hash table, ...
There are two views of an abstract data type in a procedural language like C. One is the view that
the rest of the program needs to see: the names of the routines for operations on the data
structure, and of the instances of that data type. The other is the view of how the data type and its
operations are implemented. C makes it relatively simple to hide the implementation view from
the rest of the program.
Implementation of abstract data types in C
In C, a complex data type is typically represented by a pointer to the information stored in the
data type. A C function can pass the pointer to other functions without knowing the details of
what the pointer points to. One may also use parts of a program that have been separately
compiled. All that a part of a program need know about functions it calls is their names and the
types they return.
Thus, the convention in C is to prepare two files to implement an abstract data type. One (whose
name ends in ".c") provides the implementation view; it contains the complete declaration for the
data type, along with the code that implements its associated operations. The other (whose name
1/9/14 8:17 PM Abstract data types in C
Page 2 of 3 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/ADTs.in.C.html
ends in ".h") provides the abstract view; it contains short declarations for functions, pointer
types, and globally accessible data.
The abstract data type "stack" might then be represented as follows:
stack.h
typedef struct StackStructType *StackType;

/* Return a pointer to an empty stack. */
extern StackType InitStack ( );
/* Push value onto the stack, returning success flag. */
extern boolean Push (int k);
/* Pop value from the stack, returning success flag. */
extern boolean Pop ( );
/* Print the elements of the stack. */
extern PrintStack (StackType stack);
stack.c
#include "stack.h"
#define STACKSIZE 5
struct StackStructType { /* stack is implemented as */
int stackItems [STACKSIZE]; /* an array of items */
int nItems; /* plus how many there are */
};
typedef struct StackStructType *StackType;

/*
** Return a pointer to an empty stack.
*/
StackType InitStack ( ) {
char *calloc( );
StackType stack;
stack = (StackType) calloc (1, sizeof (struct StackStructType));
stack->nItems = 0;
return (stack);
}
...
Parts of the program that need to use stacks would then contain a line
#include "stack.h"
(Often the ".c" file also includes the corresponding ".h" file, as shown above, to insure
consistency of function and type declarations.) The program would call InitStack to set up a
stack, receiving in return a pointer of type StackType; it would access the stack by passing this
pointer to Push, Pop, etc. Such a program would work no matter what the contents of stack.c,
provided only that the implemented functions performed as specified in stack.h.
One more subtlety: It occasionally happens that a module #includes more than one .h file, and
the second .h file also #includes the first. This produces compiler complaints about definitions
1/9/14 8:17 PM Abstract data types in C
Page 3 of 3 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/ADTs.in.C.html
occurring more than once. The way to avoid these complaints is to use C's conditional compiling
facility (described in K&R section 4.11.3) to make sure definitions only appear once to the
compiler. Here is an example of its use with the stack code above.
#ifndef STACK /* any suggestive variable name is fine */
#define STACK /* define it if it's not already defined */
typedef struct StackStructType *StackType;
/* Return a pointer to an empty stack. */
extern StackType InitStack ( );
/* Push value onto the stack, returning success flag. */
extern boolean Push (int k);
/* Pop value from the stack, returning success flag. */
extern boolean Pop ( );
/* Print the elements of the stack. */
extern PrintStack (StackType stack);
#endif
The first time the stack.h file is encountered, the STACK variable won't (shouldn't) have been
defined, so the body of the #ifndef is compiled. Since the body provides a definition of STACK,
subsequent inclusions of stack.h will bypass the body, thereby avoiding multiple definitions of
InitStack, Push, Pop, and PrintStack.
1/9/14 8:18 PM Solutions to sample quiz questions
Page 1 of 10 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/sample.quiz.solns.html
Solutions to sample quiz questions
Solutions to questions for "Fundamentals" quiz
1. Suppose that an integer variable n contains the value 80. Fill in the blanks in the printf
statement below so that it produces the output
80% usually
means "excellent"
printf statement:
printf (" _____ ", n);
Solution: "%d%% usually\nmeans \"excellent\". The % must be quoted with another %, not a
backslash.
2. Consider the program segment
int k;
k = getchar ( );
printf ("%d", k);
What gets printed if the user types a 2, then hits return?
Solution: Not a 2, but the decimal value of the ASCII character '2'.
3. The following program is intended to compute 5! = 120, but it prints 24 instead. What's wrong
with it?
int main ( ) {
int theNum, total;
total = 1;
theNum = 5;
while (theNum > 1) {
total *= --theNum;
}
printf ("%d", total);
return 0;
}
Solution: The decrement -- should follow theNum, not precede it.
4. What would be the effect of substituting !(theNum = 1) for the while condition theNum > 1
in the main program of exercise 3?
Solution: The expression theNum = 1 is an assignment, not a comparison. Its value is the value
assigned, namely 1. The value of ! 1 is false, since 1 is a true value. When a while loop's condition
evaluates to false, the loop is exited; thus the loop is never executed, and the value 1 is printed.
5. Fill in the blanks in the code below to convert the while loop in exercise 3 to an equivalent
1/9/14 8:18 PM Solutions to sample quiz questions
Page 2 of 10 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/sample.quiz.solns.html
for loop.
int main ( ) {
int theNum, total;
total = 1;
for ( ____ ; _____ ; _____ ) {
total *= theNum;
}
printf ("%d", total);
return 0;
}
Solution: for (theNum=5; theNum>1; --theNum) {
6. Write down the values for all variables appearing in each statement.
int main ( ) {
int x, y, z;
float a, b;
x = 3; y = 5.3; z = 2; x ____ y ____ z ____
a = 2.5; b = 3.14; a ____ b ____
/*1*/ x += y + a * z-b; x ____
/*2*/ a = b / (x%y + z) a ____
z += (x == y); z ____
/*3*/ x == (a = b); x ____
return 0;
}
Solution
x = 3; y = 5.3; z = 2; x=3 y=5 z=2
a = 2.5; b = 3.14; a=2.50 b=3.14
/*1*/ x += y + a * z-b; x=9
/*2*/ a = b / (x%y + z) a=0.523333
z += (x == y); z=2
/*3*/ x == (a = b); x=9
Where do you need parentheses to have x assigned a value of 14 in the statement
labeled /*1*/? What then is the new value of a in the statement labeled /*2*/? What is
the new value of x in the statement labeled /*3*/?
Solution: Parentheses should go around the y+a. There is no change to a in the statement labeled
/*2*/, and x retains the value 14 in the statement labeled /*3*/.
7. Predict the output of the following program. Hint: only three lines get printed. (This is
somewhat more complicated than any of the actual quiz questions.)
int main ( ) {
char c;
for (c='a'; c<'g'; ++c) {
switch (c) {
case 'a': c += 2;
case 'c': c += 1;
case 'g': ++c;
printf ("%c\n" , c-- );
default: ++c;
1/9/14 8:18 PM Solutions to sample quiz questions
Page 3 of 10 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/sample.quiz.solns.html
}
printf ("*** %c\n" , c);
}
return 0;
}
Solution: The program prints the following:
e
*** e
*** g
Solutions to questions for the "Functions and argument pointers" quiz
1. What is the output of the following program segment?
c = 'a';
putchar (c);
putchar (F(c));
putchar (c);
Assume that the function F has been defined as follows:
char F (char c) {
c = 'f';
return (c);
}
Solution: The three characters "afa" get printed. The variable c in the calling code is copied into the
local variable c in F; the assignment to c in F thus does not affect anything in the calling code.
2. Modify the code from exercise 1 so that, on return from the F function, the variable c in the
calling code contains the character 'f'.
Solution: F's parameter must now be an address so that the change can affect a variable outside the
function. Four changes are necessary:
c = 'a';
putchar (c);
putchar (F(&c)); /* first change: insert ampersand */
putchar (c);
...
char F (char *c) { /* second change: insert asterisk */
*c = 'f'; /* third change: insert asterisk */
return (*c); /* fourth change: insert asterisk */
}
3. Write a function AllDone that, given a string as argument, returns a true value if the string is
"exit" and returns false otherwise.
Two solutions:
int AllDone (char s[]) {
if (strcmp(s,"exit") == 0) {
return 1;
} else {
int AllDone (char s[]) {
return !(strcmp(s,"exit"));
1/9/14 8:18 PM Solutions to sample quiz questions
Page 4 of 10 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/sample.quiz.solns.html
return 0;
}
}
}
4. Write a function GetWordAndValue that prompts the user for a string and an integer and
returns both to the calling program. Assume that the caller has already provided space in
memory for all the characters of the word.
Solution
void GetWordAndValue (char word[], int *value) {
printf ("Type a word: ");
scanf ("%s", word);
printf ("Type an integer: ");
scanf ("%d", value); /* note that value is already a pointer */
}
5. Write a main program that calls GetWordAndValue and echoes the values returned.
Solution
#include <stdio.h>
int main ( ) {
char word[20];
int k;
GetWordAndValue (word, &k);
printf ("word is '%s', k is %d\n", word, k);
return 0;
}
Solutions to questions for "Arrays, Structures, and Files" quiz
1. Fill in the blanks in the program below so it prints the contents of the file whose name is
provided by the user.
#include <stdio.h>
int main ( ) {
char fileName[32];
char c;
FILE *inFile;
printf ("File name? ");
gets (fileName);
__________________ ;
if ( _____________ ) {
fprintf (stderr, "File doesn't exist!\n");
exit (1);
};
while ( _______________ ) { /* get a char if not done */
fprintf ( __________ ); /* print it */
}
return 0;
}
Solution: The following code goes in the blanks:
1/9/14 8:18 PM Solutions to sample quiz questions
Page 5 of 10 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/sample.quiz.solns.html
inFile = fopen (fileName, "r") ;
if (inFile == NULL) {
fprintf (stderr, "File doesn't exist!\n");
exit (1);
};
while ((c=getc(inFile))!=EOF) { /* done? */
fprintf (stdout, "%c", c); /* print it */
2. Define a struct to represent dates. The struct members should be a string representing the
month, an integer representing the date in the month, and another integer representing the
year. Then define the type Date to be synonymous with the struct definition, and define an
array dateList of five dates.
Solution
struct date {
char month[10]; /* September is the longest month name. */
int dateInMonth;
int year;
}; /* Don't forget the semicolon! */

typedef struct date Date;
Date dateList[5];
3. Fill in the blank in the code below so that it moves each element of the values array to the
immediately subsequent position in the array. The loop should discard the last value in the
array. Thus if the array contained the values 1, 2, 3, 4, and 5 before the loop, it should contain
the values 1, 1, 2, 3, and 4 after the loop.
int values[5];
...
for ( _____________________________ ) {
values[k] = values[k-1];
}
Solution: for (k=4; k>0; k--) { ... Recall that subscripts of a five-element array run from 0 to 4.
4. Modify the definition of the values array in exercise 3 so that it also initializes the array to
contain the values 1, 2, 3, 4, 5.
Solution: int values[5] = {1, 2, 3, 4, 5} or int values[ ] = {1, 2, 3, 4, 5}.
5. Write a function HasZeroDiagonal that, given a 5-by-5 integer array, returns 1 if all the
elements on the main array diagonal are zero and returns 0 otherwise.
Solution
int HasZeroDiagonal (int a[][]) {
int k, result;
result = 1;
for (k=0; k<5; k++) {
result = result && (a[k][k] == 0);
}
return result;
}
1/9/14 8:18 PM Solutions to sample quiz questions
Page 6 of 10 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/sample.quiz.solns.html
Solutions to questions for "General use of pointers" quiz
1. (Exercise 5.3 in K&R) Rewrite the strcat function given below, which uses array indexing,
to use pointers instead.
void strcat (char s[], char t[]) {
int i, j;
i = j = 0;
while (s[i] != '\0') {
i++;
}
while ((s[i++] = t[j++]) != '\0') {
}
}
Solution:
void strcat (char *s, char *t) {
while (*s != '\0') {
s++;
}
while ((*(s++) = *(t++)) != '\0') {
}
}
A more understandable way to code both versions would be to move the incrementing into the loop
body:
while ((s[i] = t[j]) != '\0') {
i++;
j++;
}
while ((*s = *t) != '\0') {
s++;
t++;
}
2. Consider the following function, intended to return a string typed by the user to the caller.
char* WordInput ( ) {
char word[20];
printf ("Type a word: ");
scanf ("%s", word);
return word;
}
What's wrong with the function? Does replacing its second line by
char* word;
fix the problem?
Solution: The problem with the function is that the twenty characters of memory allocated for the
word array, like the storage allocated for any local variable, is released when the WordInput function
exits. The return word statement returns only the pointer, not the characters pointed to, and this
1/9/14 8:18 PM Solutions to sample quiz questions
Page 7 of 10 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/sample.quiz.solns.html
pointer after exit from WordInput basically points into the phantom zone. Replacing the array
definition by the definition of a pointer is even worse. It allocates space for the pointer, but no space
at all for the characters of the string!
3. What is the meaning of the following declaration?
char* a, b;
Solution: The variable a is declared as a pointer to a char and the variable b is declared as a char.
The asterisk doesn't "distribute" over the variables. It's for this reason that we generally use one
declaration per variable.
4. Which of the following would cause compile-time or run-time problems? Please explain. Also
give the type of the right-hand side of each assignment statement, and draw a diagram for each
legal assignment to the pointer variable px.
float x, *px, a[5];
x = *px; /* 1 */
*px = x; /* 2 */
px = &x; /* 3 */
&x = px; /* 4 */
&(x+1) = x; /* 5 */
&(x)+1 = x; /* 6 */
*(&(x+1)) = x; /* 7 */
*(&(x)+1) = x; /* 8 */
x = a; /* 9 */
x = a[0]; /* 10 */
x = *(a[1]); /* 11 */
x = (*a)[2]; /* 12 */
x = a[3+1]; /* 13 */
x = a[3]+1; /* 14 */
x = &((a[3])+1); /* 15 */
x = &(a[3])+1; /* 16 */
x = *(&(a[3])+1); /* 17 */
px = a; /* 18 */
px = a[0]; /* 19 */
px = &(a[4]); /* 20 */
Solution: #4-7, #9, #11-12, #15-16, and #19 cause compile-time errors. #8 probably causes a run-
time problem. Accessing through any pointer will cause a run-time problem if the corresponding
storage has not been allocated.
x = *px; /* both floats */
*px = x; /* ditto */
px = &x; /* both pointers to floats */
&x = px; /* illegal; stores into a constant */
&(x+1) = x; /* illegal like #4 */
&(x)+1 = x; /* illegal like #4 */
*(&(x+1)) = x; /* &(x+1) is illegal */
*(&(x)+1) = x; /* stores into the variable after x! */
x = a; /* illegal; x is float, a is pointer to float */
x = a[0]; /* both floats */
x = *(a[1]); /* illegal; a[1] is float, not pointer */
x = (*a)[2]; /* illegal; (*a) is a[0] which is float */
x = a[3+1]; /* both floats */
x = a[3]+1; /* both floats */
1/9/14 8:18 PM Solutions to sample quiz questions
Page 8 of 10 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/sample.quiz.solns.html
x = &((a[3])+1); /* illegal like #5 */
x = &(a[3])+1; /* illegal: rhs is the address of a[4] */
x = *(&(a[3])+1); /* same as x = a[4] */
px = a; /* both addresses of floats */
px = a[0]; /* illegal; px is pointer to float, a[0] is float */
px = &(a[4]); /* both addresses of floats */
Diagrams for assignments to px:
#3
#18
#20
Solutions to questions for "Linked structures" quiz
1. What's the difference between the use of "." and the use of "->" in referring to a field of a
structure?
Solution: p->member is the same as (*p).member . p must therefore be declared as a pointer to a
struct.
2. Declare a type named ListPtrType that's a pointer to a struct, each instance of which
contains an integer info member and a next member that's a pointer to an instance of the
struct type.
Solution
struct listNode {
int info;
struct listNode *next;
};
typedef struct listNode *ListPtrType;
3. Write a function that returns a pointer to a newly-created node of the structure type you just
1/9/14 8:18 PM Solutions to sample quiz questions
Page 9 of 10 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/sample.quiz.solns.html
declared. Use sizeof and calloc to allocate the space for the new node.
Solution
ListPtrType newNodePtr ( ) {
return ((ListPtrType) calloc (1, sizeof(struct listNode)));
}
4. Given the following declarations
struct tnode {
char *word;
struct tnode *left, *right;
};
typedef struct tnode TREENODE, *TREEPTR;
TREEPTR tree;
TREENODE node;
indicate which of the following are legal expressions; for legal expressions, also
indicate the type of the expression.
a. node->word[2]
b. node.word[2]
c. tree->left->word
d. *(tree->left)
e. *tree->left
f. tree->*left
Solution: (a) is illegal, since node is a structure variable, not a pointer to a structure. (b) is of type
char, assuming that there are at least three characters in the word. (c) is a pointer to a char,
assuming tree is non-null. (d) is a struct tnode if tree is non-null. (e) is the same as (d) since the
precedence of " ->" is higher than that of "*". (f) is illegal.
5. What does *p++ mean?
Solution: It's the same as *(p++). The value of the expression is whatever p points to. A side effect
of the expression is that p is incremented (the expression value is whatever p pointed to before being
incremented). This is idiomatic but obnoxiously concise C usage.
6. Page 115 of K&R contains the following program to print the argument list.
int main (int argc, char *argv[]) {
while (--argc > 0) {
printf ("%s%s", *++argv, (argc > 1) ? " " : "");
}
printf ("\n");
return 0;
}
Modify this program to print the arguments on separate lines, and to omit duplicate
arguments from the argument list. If, for instance, the program is run with the command
line
1/9/14 8:18 PM Solutions to sample quiz questions
Page 10 of 10 http://inst.eecs.berkeley.edu/~selfpace/studyguide/9C.sg/Output/sample.quiz.solns.html
a.out a b a c
the output should be
a
b
c
Solution
#include <strings.h>

#define TRUE 1
#define FALSE 0
typedef int boolean;

/* this program prints out all unique command line arguments */
boolean not_dup (char *arg, char ** argv);
int main (int argc, char **argv) {
int i; char **arg;
for (i = 1, arg = argv+1; i<argc; i++, arg++) {
/* Loop through arguments */
/* (ignore the first, which is a cmd, not an argument) */
if (not_dup(*arg, argv)) { /* print unique args */
puts(*arg);
}
}
return 0;
}

/* "Walk" down the list of arguments until arg matches the item */
/* in argv. If the pointer to that item is the same as arg, then there */
/* aren't any duplicates before the item itself. */
boolean not_dup(char *arg, char ** argv) {
char **arg_item;
for (arg_item = argv+1; *arg_item < arg ; arg_item++) {
/* Check all items before arg */
if (strcmp(*arg_item, arg) == 0) { /* and compare */
return(FALSE); /* return false if match is found */
}
}
return(TRUE); /* If no dups found then this item must be unique */
}

You might also like