Kodewick
Lesson 25 of 30Contents

typedef and enum

Lesson 25 of 30 · Part 5 · Your own types · about 15 minutes

For the last two lessons, every use of a struct meant writing struct student, which gets wordy. typedef gives a type a new name, so there's less to write:

main.c
1#include <stdio.h>2 3typedef struct {4    char name[20];5    int score;6} Student;7 8int main(void) {9    Student s = { "Ana", 95 };10    Student t = { "Ben", 88 };11    printf("%s: %d\n", s.name, s.score);12    printf("%s: %d\n", t.name, t.score);13    return 0;14}
Output
Ana: 95
Ben: 88

Student is the name of this struct, with no struct in front. This lesson covers typedef, and something often used along with it: enum.

typedef makes an alias

You write it as typedef old_type new_name;. It doesn't create a new type; it only gives the existing type one more name, and the two names work exactly the same:

main.c
1#include <stdio.h>2 3typedef int Minutes;4 5Minutes total(Minutes a, Minutes b) {6    return a + b;7}8 9int main(void) {10    Minutes run = 25;11    Minutes walk = 40;12    printf("%d minutes in all\n", total(run, walk));13    return 0;14}
Output
65 minutes in all

Minutes is int, and you still print it with %d. The benefit is that a reader can see at a glance what the number is: minutes, not just any integer. You've already used a name like this: size_t, the type strlen returns, is a name the standard library made with typedef. Behind it is an integer type with no negative numbers.

typedef struct

The most common use is naming a struct. The first example defined the struct and named it in one go. Split into two steps, it looks like this, and means the same:

main.c
1#include <stdio.h>2 3struct point {4    int x;5    int y;6};7 8typedef struct point Point;9 10int main(void) {11    Point a = { 3, 4 };12    struct point b = { 1, 2 };13    printf("(%d, %d) and (%d, %d)\n", a.x, a.y, b.x, b.y);14    return 0;15}
Output
(3, 4) and (1, 2)

Point and struct point are the same type, and you can mix the two. That's why you'll often see it written all at once, giving you both names:

1typedef struct point {2    int x;3    int y;4} Point;

The point before the curly brace can be left out (the first example did). When is it required? When the struct needs to refer to itself, like a node in a linked list that points to the next node. That's the next lesson.

enum: integers with names

An order can only be in a few states: pending, paid, shipped, delivered. You could use 0, 1, 2 and 3, but a few days later you'll have forgotten what status == 2 means. An enumeration (enum) gives each of these numbers a name:

main.c
1#include <stdio.h>2 3enum status { PENDING, PAID, SHIPPED, DELIVERED };4 5int main(void) {6    enum status s = SHIPPED;7    printf("PENDING = %d\n", PENDING);8    printf("DELIVERED = %d\n", DELIVERED);9    printf("s = %d\n", s);10    if (s == SHIPPED) {11        printf("It has shipped\n");12    }13    return 0;14}
Output
PENDING = 0
DELIVERED = 3
s = 2
It has shipped

Without numbers, the first name is 0 and each one after it is 1 more. The names really are int constants: you can compare them and print them with %d. By habit they're written in all capitals, so you can tell they're constants.

Choosing the numbers

You can also give a name a number. A name with a number uses it; the ones after it without a number keep counting up by 1. For example, to make Monday 1:

main.c
1#include <stdio.h>2 3enum weekday { MON = 1, TUE, WED, THU, FRI, SAT, SUN };4 5int main(void) {6    enum weekday today = WED;7    printf("Today is day %d of the week\n", today);8    printf("%d days until Sunday\n", SUN - today);9    return 0;10}
Output
Today is day 3 of the week
4 days until Sunday
Guess first

What does this program print?

1#include <stdio.h>2 3enum level { LOW = 1, MIDDLE, HIGH = 10, TOP };4 5int main(void) {6    printf("%d %d\n", MIDDLE, TOP);7    return 0;8}

switch on an enum

enum and switch go together naturally: one case per state, and names are much clearer than numbers. The function below turns a state into words:

main.c
1#include <stdio.h>2 3typedef enum { PENDING, PAID, SHIPPED, DELIVERED } Status;4 5void show_status(Status s) {6    switch (s) {7        case PENDING:8            printf("Waiting for payment\n");9            break;10        case PAID:11            printf("Paid\n");12            break;13        case SHIPPED:14            printf("On its way\n");15            break;16        case DELIVERED:17            printf("Delivered\n");18            break;19    }20}21 22int main(void) {23    show_status(PAID);24    show_status(DELIVERED);25    return 0;26}
Output
Paid
Delivered

typedef enum { ... } Status; works like typedef struct: it gives the enum a short name, so from then on you just write Status. Don't forget the break after each case (lesson 5).

Putting them together

A struct can have an enum member. Here is a list of orders, each with a number and a state, and we count how many haven't arrived yet:

main.c
1#include <stdio.h>2 3typedef enum { PENDING, PAID, SHIPPED, DELIVERED } Status;4 5typedef struct {6    int id;7    Status status;8} Order;9 10int main(void) {11    Order orders[4] = { { 1001, DELIVERED }, { 1002, SHIPPED }, { 1003, PAID }, { 1004, DELIVERED } };12    int waiting = 0;13    for (int i = 0; i < 4; i++) {14        if (orders[i].status != DELIVERED) {15            printf("Order %d hasn't arrived\n", orders[i].id);16            waiting++;17        }18    }19    printf("%d still on the way\n", waiting);20    return 0;21}
Output
Order 1002 hasn't arrived
Order 1003 hasn't arrived
2 still on the way

Press Step: each Order is a box, and its status cell holds just an integer.

Tip: C doesn't check that an enum variable holds one of the listed numbers: Status s = 7; compiles fine. So it's a good idea to add a default to the switch, to handle numbers you didn't expect.

Practice

Write the code, then press Check. A hint costs nothing; the answer is there when you need it.

Exercise 1

Rectangle

Use typedef struct to define Rect with the members width and height (both int). Write a function area that takes a Rect and returns its area. The program should print Area: 24.

It should print
Area: 24
exercise1.c
1#include <stdio.h>2 3// define Rect and area here4 5int main(void) {6    Rect r = { 4, 6 };7    printf("Area: %d\n", area(r));8    return 0;9}
Output
Press Run or Ctrl+Enter
Exercise 2

Cup sizes

Write a function price that takes a Size and uses switch to return the price: SMALL is 12, MEDIUM is 15, LARGE is 18. The program should print 12 15 18.

It should print
12 15 18
exercise2.c
1#include <stdio.h>2 3typedef enum { SMALL, MEDIUM, LARGE } Size;4 5int price(Size s) {6 7}8 9int main(void) {10    printf("%d %d %d\n", price(SMALL), price(MEDIUM), price(LARGE));11    return 0;12}
Output
Press Run or Ctrl+Enter
Exercise 3

Turn right

The directions go clockwise: north, east, south, west. Write a function turn_right that returns the direction after a right turn: north becomes east, and so on, and west goes back to north. The program starts facing north and turns 5 times, printing each new direction; the last line is East.

It should print
East
South
West
North
East
exercise3.c
1#include <stdio.h>2 3typedef enum { NORTH, EAST, SOUTH, WEST } Direction;4 5Direction turn_right(Direction d) {6 7}8 9int main(void) {10    char names[4][8] = { "North", "East", "South", "West" };11    Direction d = NORTH;12    for (int i = 0; i < 5; i++) {13        d = turn_right(d);14        printf("%s\n", names[d]);15    }16    return 0;17}
Output
Press Run or Ctrl+Enter

What you learned

  • typedef old_type new_name; gives a type an alias without making a new type; that's where size_t comes from.
  • After typedef struct { ... } Student; you just write Student, with no struct; a struct that refers to itself needs a name before the curly brace.
  • enum names a set of integers: by default they start at 0 and go up by 1; you can set your own, and the ones after count up from there.
  • Enum names are int constants: you can compare them and print them with %d, and they're written in capitals by habit.
  • switch on an enum with one case per value; C doesn't check what an enum holds, so add a default.