CS16, Summer 2012

C Structures

Goals for this lab

By the time you have completed this lab, you should be able to

Step by Step Instructions

Step 1: Get together with your lab partner, and create a lab08 directory

This lab's first pilot should log in, create ~/cs16/lab08/ and make that your current directory.

Step 2: Practice using a struct at the ch prompt

Start ch. Then define the following structure to represent a playing card:

ch> struct card { char suit; int face; };

By the way, when not using ch, we define structs over several lines like this:

struct card {
    char suit;
    int face;

An object of this type will hold a char variable named suit to represent the card's suit (assumed to be 'C' for Clubs, 'D' for Diamonds, 'H' for Hearts and 'S' for Spades), and an int variable named face to represent its face value (2-10 for two through ten, 11 for jack, 12 for queen, 13 for king and 14 for ace)

Create a struct card object named c, and set its fields to represent the ace of Spades. Then type the object's name by itself to see how ch displays structs:

ch> struct card c;
ch> c.suit = 'S';
ch> c.face = 14;
ch> c
.suit = S
.face = 14

Create a pointer to a struct card object named cp, set it to the address of c:

ch> struct card *cp = &c;

Now cp can be used as another way to access the fields of c. To do so you must first dereference the pointer, *cp, and then apply the dot operator to access the field. Since the dot operator "binds more tightly" (has higher precedence) than the dereference operator, the first part has to be inside parentheses, and because that syntax is so awkward, the C language authors provided '->' as a shortcut pointer operator. Practice both at the ch prompt: use the awkward syntax to display c's suit, and use the pointer operator to display c's face:

ch> (*cp).suit
ch> cp->face

C programmers grow weary of two-word type names, and the language authors gave us some relief for that annoyance too. The keyword typedef can be used to create a nickname for an existing type. For example, the statement 'typedef int Integer' would define Integer as a nickname for the int data type - from then on, Integer can be used anywhere that int is used.

Nicknames for structs traditionally are the struct tag with the first letter capitalized. Define type Card as a nickname for struct card:

typedef struct card Card;

Now use the nickname to create another struct card object named c2, but also use an "initializer list" to set this card's fields to represent the queen of Hearts:

ch> Card c2 = {'H', 12};
ch> c2
.suit = H
.face = 12

Notice that you cannot use relational operators to compare entire structures like Card objects. Instead you must compare individual fields:

ch> c2 < c
ERROR: invalid operands for less than operator <
ch> c2.face < c.face

It is appropriate to use relational operators for comparing pointers to structures though: both == and != any time, and the other operators when the pointers both refer to the same array. (a) Create another Card pointer named cp2, and assign the address of c2 to it. (b) Then use == to compare cp to cp2. (c) Aim cp2 at c. (d) Compare cp to cp2 again:

ch> Card *cp2 = &c2;
ch> cp2 == cp
ch> cp2 = &c;
ch> cp2 == cp

Understand these results before proceeding to Step 3.

Step 3: Write and test functions that process structs

First: switch roles between pilot and navigator if you did not already do that.

Exit ch.

Study the completed parts of this cards.c skeleton.

Get a copy of the skeleton program in your lab08 directory:

cp ~kyledewey/cs16/lab08/cards.c ~/cs16/lab08/

After all of printCard, printCards and cmpCards are completed, your results should match the following:

-bash-4.1$ make cards
cc     cards.c   -o cards
-bash-4.1$ ./cards
printing third card: seven of Clubs

printing first two cards:
ace of Spades
queen of Hearts

printing all cards, unsorted:
ace of Spades
queen of Hearts
seven of Clubs
seven of Diamonds
jack of Spades

printing all cards, sorted:
seven of Clubs
seven of Diamonds
jack of Spades
queen of Hearts
ace of Spades

Open cards.c in an editor, and make the following changes. But don't do them all at once - instead test each part before continuing to the next part. You can even compile/run the original version - it just doesn't do anything:

-bash-4.1$ ./cards
printing third card:
printing first two cards:

printing all cards, unsorted:

printing all cards, sorted:
  1. Type your name(s) in the comment at the top. Then scroll down past the main function to edit the ones below it.
  2. Implement printCard to neatly print the face and suit of one Card object, and then a newline character. See the sample results to know exactly how it should work. Did you study the global array named faces and the function named suit at the top of the program? You will find that printCard is very easy to do if you use these features properly. Remember that "%s" is the format specifier to use for printing strings with printf.
  3. Implement printCards to neatly print the first n elements of the array cards, each on a separate line. Of course you should use printCard to simplify this part.
  4. Implement cmpCard to compare two Card objects by their face values. You learned about the function named strcmp from the string.h library, and this one should work in a similar way. This type of comparison function is quite common, partly because the C library function qsort strictly depends on such a function - it returns an int to indicate how two objects are related, less than 0 if the first object is less than the second one, greater than 0 if the first object is greater than the second one, and exactly 0 if the objects are equal. It is important to notice that pointers are passed in as parameters - uses these pointers to access the face value of each Card object, and return an int that indicates how the two face values are related.

Remember to save the file and test after completing each function. Don't wait to test them all at once.

Step 4: Get credit for the lab

Don't leave early though ... see challenge problems below.

Submit your code with the turnin program. You MUST have both your name and your partner's name in the file in order to receive credit. Remember that the original pilot needs to do this step, since that is whose account you have been using in Cooper Lab.

Bring up a terminal window on CSIL or the Cooper Lab, and cd into the original pilot's cs16 directory, and cd again into the lab08 directory. Then type the following to turn in the file from Step 3 above:

turnin lab08@cs16 cards.c

Respond "yes" when the program asks if you want to turn in (be sure to read the list of files you are turning in), and then wait for the message indicating success.

Evaluation and Grading

Each student must accomplish the following to earn full credit for this lab:

Deadline for lab submission: Wednesday 8/22 (11:59pm)

Optional Extra Challenge

Adapted by Kyle Dewey from a lab prepared by Michael Costanzo.