5.1.26 · D4C Programming

Exercises — Typedef

2,447 words11 min readBack to topic

Remember the one trick that unlocks every problem (from Typedef):


Level 1 — Recognition

Goal: can you spot what a typedef names, without running anything?

L1.1

typedef unsigned char Byte;

Q: What existing type does Byte name?

Recall Solution

Cover typedefunsigned char Byte; declares a variable Byte of type unsigned char. Therefore Byte is an alias for ==unsigned char==. A smaller sanity check: unsigned char holds values to (that is ), which is why "Byte" is a fitting nickname.

L1.2

typedef double Real;
Real pi = 3.14;

Q: After this, is Real pi = 3.14; legal, and what is pi's real type?

Recall Solution

Yes, legal. Real is double, so Real pi = 3.14; is identical to double pi = 3.14;. typedef creates a name, not a new kind of thing — pi is a plain double.

L1.3

typedef char *String;

Q: Is String an alias for char, or for char *?

Recall Solution

Cover typedefchar *String;. The * binds to the name String, not to char. So String would be a variable of type char *. Therefore String = ==char *== (pointer to char), not char.


Level 2 — Application

Goal: use a typedef to write shorter, correct code.

L2.1

Given:

struct Point { int x, y; };
typedef struct Point Point;

Q: Write a line declaring a Point called p and setting p.x = 3, p.y = 4.

Recall Solution
Point p;
p.x = 3;
p.y = 4;

Why this works: without the alias you'd need struct Point p; because in C the struct tag Point lives in a separate namespace. The typedef puts Point into the ordinary type namespace, so you may drop the struct keyword. See Structures in C.

L2.2

typedef int* IntPtr;
IntPtr a, b;

Q: What are the types of a and b?

Recall Solution

Both a and b are int*. The * is baked inside the alias IntPtr. When you write IntPtr a, b; each variable independently gets the whole aliased type. So a is int* and b is int*.

L2.3

typedef unsigned int uint;
uint x = 5;
uint y = 4294967295;   /* 2^32 - 1 */

Q: On a system where unsigned int is 32 bits, what is x + 1 and what is y + 1?

Recall Solution

uint is unsigned int, so arithmetic wraps around modulo .

  • x + 1 = 6.
  • The value is the largest representable value, so y + 1 wraps back to . The alias changed nothing about behaviour — it is still unsigned int.

Level 3 — Analysis

Goal: predict differences and explain why.

L3.1

#define INTPTR int*
typedef int* IntPtr;
 
INTPTR  a, b;
IntPtr  c, d;

Q: Classify each of a, b, c, d as int or int*.

Recall Solution

#define is dumb text replacement by the preprocessor. INTPTR a, b; literally becomes:

int* a, b;   // a is int*, b is int

So a = int*, b = int.

typedef is a real type alias understood by the compiler. IntPtr c, d; gives each variable the whole type:

  • c = int*, d = int*.

Summary: a = int*, b = int, c = int*, d = int*. This is the crucial typedef vs #define split from Pointers in C.

L3.2

Decode this declaration using the cover-typedef trick:

typedef int (*Operation)(int, int);

Q: What type is Operation?

Recall Solution

Cover typedefint (*Operation)(int, int);. Read the declarator from the identifier outward:

  1. Operation is the name.
  2. (*Operation) — the parentheses force * to bind first: Operation is a pointer to something.
  3. (...)(int, int) — that something is a function taking (int, int).
  4. The leading int is the return type.

Therefore Operation = "pointer to a function taking two ints and returning int". See Function Pointers.

L3.3

typedef int Money;
Money price = 100;   // 100 rupees

Later the project needs cents (fractions), so someone changes the alias to:

typedef double Money;

Q: How many lines of usage code must change, and what value does Money price = 100; now hold?

Recall Solution

Zero usage lines change — that is the whole point of portability. Only the single typedef line changed. After the change Money is double, so Money price = 100; stores 100.0 (a double). price / 3 now gives a fractional result instead of the truncated integer 33. This shows why aliasing a policy type (like "how we store money") behind one name is powerful: change once, everything follows.


Level 4 — Synthesis

Goal: build multi-piece type designs yourself.

L4.1

Q: Write a typedef for an array of 4 Operations (using Operation from L3.2), giving the array type its own alias OperationTable4. Then show how to call the third stored operation on (2, 3).

Recall Solution
typedef int (*Operation)(int, int);   // from L3.2
typedef Operation OperationTable4[4]; // NEW alias: array of 4 Operations
 
OperationTable4 table;    // 'table' is an array of 4 function pointers
// suppose table[2] = add;  where int add(int,int){...}
int r = table[2](2, 3);   // calls add(2,3)

How to read the new typedef: cover typedefOperation OperationTable4[4]; declares OperationTable4 as an array of 4 Operations. So the identifier OperationTable4 becomes the alias, and its meaning is "array of 4 function pointers". Why the alias earns its keep: without any alias, this type is written int (*table[4])(int, int); — nearly unreadable. With the two typedefs, OperationTable4 table; reads like plain English. The third stored operation is table[2]; calling add(2,3) where int add(int a,int b){return a+b;} yields ==5==.

L4.2

Q: Using an anonymous struct, write a single typedef that makes Vec2 a type with float x, y;. Then declare Vec2 v = {1.5f, 2.5f}; and compute v.x + v.y.

Recall Solution
typedef struct { float x, y; } Vec2;
Vec2 v = {1.5f, 2.5f};
float s = v.x + v.y;   // s = 4.0

Why anonymous? We never need to refer to the struct by a tag, only by the alias Vec2, so we skip naming the tag entirely. v.x + v.y = 1.5 + 2.5 = ==4.0==. See Structures in C.

L4.3

Q: For a linked list, write the typedef so that Node means struct node, allowing a self-referential pointer next. Then state what sizeof(Node) roughly contains on a 64-bit system (assume int = 4 bytes, pointer = 8 bytes, before padding).

Recall Solution
typedef struct node {
    int  data;
    struct node *next;   // must use the TAG here, alias not visible yet
} Node;

Why the tag node is still needed: inside the struct body the alias Node does not exist yet (the typedef name is only usable after the closing brace), so the self-reference must use struct node *. Raw member sizes: int data = 4 bytes, struct node *next = 8 bytes → 12 bytes of data. With alignment, the compiler pads to a multiple of 8, giving sizeof(Node) = 16 bytes. See Linked Lists and Pointers in C.


Level 5 — Mastery

Goal: reason at the edge — degenerate and tricky cases.

L5.1

Q: Is the following legal, and if so what does it do?

typedef int Integer;
typedef Integer Whole;
Whole n = 7;
Recall Solution

Legal. A typedef may alias another alias. Chain: WholeIntegerint. So Whole n = 7; is just int n = 7;. Aliasing is transitive; there is no "new type" at any step, only names pointing at int.

L5.2

Q: Given

typedef int Arr[3];
Arr a;

what is the type of a, and what is sizeof(a) (with 4-byte int)?

Recall Solution

Cover typedefint Arr[3]; declares Arr as an array of 3 ints. So the alias Arr means "array of 3 int". Arr a; therefore makes a an array of 3 int. sizeof(a) = 3 × 4 = ==12== bytes. This is the surprising power (and danger) of array typedefs: the array-ness is hidden inside the name.

L5.3

Q: With typedef int Arr[3];, consider a function void f(Arr x). Does x inside f behave as an array of 3 ints, or as a pointer? What is sizeof(x) inside f on a 64-bit system?

Recall Solution

A degenerate/edge case. In C, any array parameter — even one hidden behind a typedef — decays to a pointer. So void f(Arr x) is really void f(int *x). Inside f, x is a pointer, so sizeof(x) = ==8== bytes (pointer size on 64-bit), not 12. Lesson: the alias hides the array type, but the array-to-pointer decay rule still applies at function boundaries — the name did not change the language's behaviour, only its spelling.


How the levels build

The ladder is deliberate — each level reuses the rung below and adds exactly one new idea:

Level New idea it adds The one thing you must carry up
L1 Recognition Spot what an alias names An alias is a name, nothing more
L2 Application Use the alias (struct, pointer, wraparound) Behaviour = the underlying type's behaviour
L3 Analysis typedef vs #define Compiler alias ≠ text substitution
L4 Synthesis Build fn-ptr arrays, structs, list nodes Aliases can nest and self-reference
L5 Mastery Array aliases, chains, parameter decay The name never changes language rules
Recall

One rule that survives every level ::: typedef makes a name, never a new type — behaviour (wraparound, decay, size) is exactly that of the underlying type. Why Arr x as a parameter has size 8 not 12 ::: array parameters decay to pointers in C, even through a typedef.

Connections