CMSC 14300: Practice Set 5 - Structs, Enums, and Unions¶
Practice for the material in Week 4: defining and using structs, arrays of
structs, pointers to structs and the -> operator, structs that own heap memory,
typedef, enum, and union. None of these repeats a lecture or homework
exercise; together they drill the new moves - group fields into a type, reach them
with . and ->, change a struct through a pointer, and tag a union. This is good
preparation for the next quiz.
Work in a fresh directory and compile everything with warnings on. Some problems
need <stdlib.h> (for malloc/free) and <string.h> (for strlen/strcpy):
mkdir -p ~/cmsc14300/lec07-pset && cd ~/cmsc14300/lec07-pset
clang -Wall -Wextra -std=c17 problem1.c -o problem1
Keep last week's memory rules in view: every malloc still has exactly one free,
and a struct copy does not copy what a pointer member points at.
Problem 1 - Distance between two points in 3D¶
Model a point in three dimensions as a struct, and write a function that returns the
straight-line distance between two of them. Both points are passed by value,
and the answer comes back as a double.
struct point3d { double x; double y; double z; };
double distance(struct point3d a, struct point3d b);
- The distance is
sqrt((a.x-b.x)^2 + (a.y-b.y)^2 + (a.z-b.z)^2). Include<math.h>forsqrt, and compile with-lmif your system needs the math library:clang -Wall -Wextra -std=c17 problem1.c -o problem1 -lm. - Reach each member with the dot operator (
a.x,b.z). The inputs are copies, so nothing you pass is disturbed; the result is returned by value. - Check with
(0,0,0)and(3,4,0), which are5apart.
Problem 2 - The hottest day (array of structs)¶
Define a struct for a daily temperature reading, fill a small array of them, and report the hottest day and the average temperature. This is a table of records scanned by one of its fields.
- Initialize an array such as
{ {1, 22.5}, {2, 19.0}, {3, 31.2}, {4, 26.0} }. - Walk the array once: track the index of the largest
celsius(seed from element 0) and sum everycelsiusinto a runningdouble. Index first, then dot:readings[i].celsius. - Print the winning day's
dayandcelsius, then the average (sum / n, as adouble). - Check your understanding: why does
readings[i].dayreach the day of elementi, butreadings.day[i]does not even compile?
Problem 3 - Rename a playlist (pointer to struct + heap-owned string)¶
A struct owns a heap-allocated title. Write a function that replaces that title through a pointer: it frees the old string and installs a fresh copy of the new one. This is the pointer-to-struct move combined with last week's ownership rules.
struct playlist {
char *title; /* heap string this struct owns */
int length; /* number of songs */
};
void set_title(struct playlist *p, const char *new_title);
- In
set_title:free(p->title);first (the old string), thenp->title = malloc(strlen(new_title) + 1);, check forNULL, andstrcpythe new characters in. Use->becausepis a pointer. - In
main: build a playlist whosetitleyou allocated the same way (or start with a firstset_titleon a struct whosetitleisNULL- freeingNULLis safe), print it, rename it, print again, thenfree(p->title)at the end. - Check your understanding: what goes wrong if
set_titlemallocs the new title but forgets tofreethe old one first? Which of last week's two bugs is that? - Run under
valgrindto confirm no leak and no use-after-free.
Problem 4 - Count out the change (typedef + enum)¶
Use a typedef'd enum to name the U.S. coins, and write a function that returns
a coin's value in cents. Then sum an array of coins.
typedef enum { PENNY, NICKEL, DIME, QUARTER } Coin;
int coin_value(Coin c); /* cents: 1, 5, 10, 25 */
int total_cents(const Coin *coins, int n);
- Implement
coin_valuewith aswitchon the enum (onecaseper coin returning its cent value).total_centswalks the array and adds upcoin_value(coins[i]). - In
main, build an array like{QUARTER, DIME, NICKEL, PENNY}and print the total. The enum names read like the intent; no bare0/1/2literals. - Check your understanding: what integer values do
PENNY,NICKEL,DIME,QUARTERhave by default, and why is that separate from their cent values?
Problem 5 - A cell that is a number or a label (tagged union)¶
Model a spreadsheet cell that holds either a number or a short text label,
using an enum tag and a union. A function prints the cell by checking the tag
first.
typedef enum { CELL_NUMBER, CELL_TEXT } CellKind;
typedef struct {
CellKind kind;
union {
double number; /* valid when kind == CELL_NUMBER */
char text[16]; /* valid when kind == CELL_TEXT */
};
} Cell;
void print_cell(const Cell *c);
print_celldoes aswitch (c->kind): forCELL_NUMBERprintc->number, forCELL_TEXTprintc->text. Read the union member only after checking the tag.- In
main, build one of each with designated initializers:Cell a = {.kind = CELL_NUMBER, .number = 42.5};andCell b = {.kind = CELL_TEXT, .text = "hello"};. Pass&aand&bto the printer. - Check your understanding: roughly how large is one
Cell- closer to the size of adoubleor the size ofdouble + char[16]? Why? And what does thekindfield record that theunionalone cannot?
Self-check¶
You're ready for the upcoming quiz material if you can, without looking it up:
- Define a
struct, declare a variable of it, and reach its members with.; explain why the definition needs a trailing semicolon. - Explain what it means that a struct is a value: what a plain assignment copies, and why a function taking a struct by value cannot change the caller's struct.
- Reach a member through a pointer with
->, and state whatp->xis shorthand for. Say when you take astructparameter by value, by pointer, and byconstpointer. - Write a
structthat owns a heap string: allocatestrlen(s) + 1, copy the characters in, and free it exactly once. Explain why a struct copy does not duplicate the string. - Use
typedefto drop thestruct/enumkeyword, and write a smallenumused in aswitch. - Say how a
uniondiffers from astructin size and in how many members are valid at once, and why a tagged union (anenumtag plus aunion) is the safe way to use one.