Structs and Dynamic Memory Management, C 101 – Study Notes
offline

Computer Science I (University of Central Florida)

Tags: struct, typedef, array of structs, dot operator, malloc, calloc, realloc, free, sizeof, stack vs heap, dynamic memory allocation, deep copy, memory deallocation

Difficulty: Intermediate | Prerequisites: C Basics, Pointers, Strings


Big Picture

Structs let you bundle different data types under one name, which is how C models real-world entities (students, books, video games) without classes or objects. Dynamic memory management gives your programme the ability to request exactly as much memory as it needs at runtime, rather than fixing everything at compile time. Together, these two concepts are the gateway to building flexible data structures like linked lists and trees. You need solid pointer skills before tackling this section, because every malloc returns a pointer and every free expects one.


TL;DR

A struct groups variables of different types under one name, accessed with the dot operator. Arrays hold same-type elements; structs hold mixed types. malloc allocates memory on the heap and returns a pointer to it. free releases that memory. When a struct contains pointers to dynamically allocated data (like strings), you must free the inner allocations before freeing the struct itself. Exam questions frequently test this deallocation order.


Key Terms

struct

A user-defined type that groups variables of different types under a single name. Members are accessed with the dot (.) operator. Think of it as a custom container: a student struct might hold an int for ID, a char[] for name, and a float for grade, all in one package.

typedef

A keyword that creates an alias for a type, so you do not have to write struct every time. typedef struct { ... } book_t; lets you use book_t directly. In simple terms, it is a nickname for a type.

Dot operator (.)

Used to access a member of a struct variable. student.name gets the name field from the student struct.

Arrow operator (->)

Used to access a member of a struct through a pointer. ptr->name is shorthand for (*ptr).name.

sizeof

An operator that returns the number of bytes occupied by a type or variable. Used with malloc to allocate the correct amount of memory: malloc(n * sizeof(int)).

malloc()

Allocates a block of memory of the requested size (in bytes) on the heap and returns a pointer to the start of that block. The memory is not initialised. In simple terms, you are asking the operating system for a chunk of raw memory.

realloc()

Resizes a previously allocated memory block. If the block can be extended in place, it does so; otherwise it allocates a new block, copies the data, and frees the old one.

free()

Releases a previously allocated block of heap memory. After calling free(ptr), the pointer still holds the old address (a dangling pointer), so best practice is to set it to NULL immediately.

Stack memory

The memory region used for static/local variable allocation. Managed automatically: variables are created when a function is entered and destroyed when it returns.

Heap memory

The memory region used for dynamic allocation (malloc, calloc, realloc). Managed manually: you must explicitly free what you allocate, or you leak memory.

Deep copy

A copy where every dynamically allocated component is independently duplicated. The copy has its own separate memory, so freeing one does not affect the other. Think of it as photocopying every page of a document rather than just copying the table of contents.


Core Content

Struct vs. Array

  • An array stores elements of the same type, accessed by index (arr[0], arr[1], ...)

  • A struct stores members of potentially different types, accessed by name (student.id, student.grade)

  • Both can be passed to functions, but arrays decay to pointers while structs are passed by value (a full copy) unless you use a pointer

Defining and Using Structs

  • Basic definition:

    struct Student {    int id;    char name[50];    float grade;};
    
  • With typedef:

    typedef struct {    char *name;    int year;    double price;} videogame_t;
    
  • Access members with . for struct variables, -> for struct pointers

  • A struct can include another struct as a member (nested structs). This is true and commonly tested.

Arrays of Structs

  • Declare an array of structs just like any array:

    struct Student students[3] = {    {101, "Alice", 89.5},    {102, "Bob", 76.0},    {103, "Charlie", 92.3}};
    
  • Access elements with combined array and dot syntax: students[i].name

  • This pattern is the foundation for managing collections of records (databases, inventories, libraries)

Euclidean Distance with Structs

  • Define a struct Point with float x and float y

  • The distance formula: sqrt(dx dx + dy dy) where dx = p2.x - p1.x and dy = p2.y - p1.y

  • Requires #include for sqrt()

Dynamic Memory Allocation

  • malloc(size) allocates size bytes on the heap, returns a void *

  • Always calculate size using sizeof: malloc(n * sizeof(int)) for an array of n integers

  • Always check the return value; malloc returns NULL if allocation fails

  • Static allocation uses the stack; dynamic allocation uses the heap

Deep Copy Pattern

When a struct contains pointer members (dynamically allocated strings, arrays of pointers), a shallow copy just copies the pointer values. Both the original and the copy then point to the same heap memory, which is dangerous. A deep copy allocates new memory for each pointer member and copies the actual data.

Example from the course (video game inventory):

  • Allocate a new array: malloc(n * sizeof(videogame_t))

  • For each matching element, copy simple members directly (year, price)

  • For string members, allocate fresh memory: malloc(sizeof(char) * (1 + strlen(source.name)))

  • Copy the string with strcpy()

  • After filtering, realloc the result array down to the actual count

  • Set the count via a pointer parameter: *ptrNumGames = nG

Memory Deallocation (the cleanUp pattern)

When freeing a struct that contains dynamically allocated members, you must free from the inside out:

  1. Free each individual string in any array of strings (sentences[sIndex])

  1. Free the array of string pointers itself (sentences)

  1. Free other dynamically allocated members (title, author)

  1. After processing all structs in the array, free the array of structs itself (lib)

Setting pointers to NULL after freeing is good practice to avoid dangling pointer bugs.

The book_t example from a Spring 2025 exam:

void cleanUp(book_t *lib, int numBooks) {
    for (int bIndex = 0; bIndex < numBooks; bIndex++) {
        // Free each sentence string
        for (int sIndex = 0; sIndex < lib[bIndex].numSentences; sIndex++) {
            free(lib[bIndex].sentences[sIndex]);
        }
        // Free the array of sentence pointers
        free(lib[bIndex].sentences);
        // Free title and author strings
        free(lib[bIndex].title);
        free(lib[bIndex].author);
    }
    // Free the array of structs
    free(lib);
}

Note: the exam version copies lib[bIndex] into a local curBook, which means the NULL assignments after each free only affect the local copy, not the original array. This is a subtle point, but the deallocation itself still works because free operates on the address, not the variable holding it.


Formulas / Diagrams

malloc size for an array of structs:

malloc(count * sizeof(struct_type))

malloc size for a string copy:

malloc(sizeof(char) * (strlen(source) + 1))

The + 1 accounts for the null terminator.

Deallocation order (inside out):

Inner allocations → container pointer → outer struct array


Real-World Applications

Operating systems use structs to represent processes, files, and network connections. Game engines store entities (characters, items, enemies) as structs or struct-like objects. Dynamic memory management is how any programme handles data whose size is not known at compile time: reading a file of unknown length, building a data structure that grows, or managing a pool of network connections.


Common Misconceptions

  • Students sometimes try to compare or assign structs member-by-member using == or = on the whole struct. C does allow direct struct assignment (s2 = s1), but this is a shallow copy. If the struct contains pointers, both copies share the same heap data.

  • Students forget the + 1 when allocating space for a string copy. The null terminator needs its own byte. Omitting it causes buffer overflow.

  • Students sometimes free the outer array first and then try to access the inner pointers, which are now in freed memory. Always free from the inside out.

  • Students confuse stack and heap: local variables live on the stack and are automatically cleaned up. malloc'd memory lives on the heap and must be freed manually.


Why It Matters / Exam Flags

⚠️ The dot operator (.) accesses struct members. Expect a multiple-choice question on this.

⚠️ A struct can include another struct as a member. True/false favourite.

⚠️ sizeof returns the number of bytes. Know how to use it with malloc.

⚠️ malloc takes the size in bytes and returns the address of the allocated memory. Fill-in-the-blank format.

⚠️ Stack is for static allocation; heap is for dynamic allocation. Fill-in-the-blank format.

⚠️ The cleanUp / deallocation pattern (freeing inner allocations before outer) appears on nearly every exam. Practise writing it from memory.

⚠️ Deep copy questions (like the getClassicGames function) require you to allocate new memory for every pointer member and copy data with strcpy. Do not forget the + 1 for string length.

⚠️ For storing related information of different data types, the answer is struct. For related information in general (same or different types), the answer is "all of these" (array, string, struct).


Quick Self-Test

  1. True or false: A struct can include another struct as a member variable.

  1. Fill in the blank: malloc allocates memory on the ___.

  1. What operator accesses a struct member through a pointer?

  1. True or false: Static allocation uses the heap.

  1. When freeing a struct with dynamically allocated string members, which do you free first: the strings or the struct?

Answers: 1. True 2. heap 3. -> (arrow operator) 4. False (it uses the stack) 5. The strings (inner allocations first)


Practice Q&A

Q: What is the difference between a struct and an array?

A: An array stores elements of the same data type, accessed by index. A struct groups variables of different types under one name, accessed with the dot operator.

Q: Write the malloc call to allocate space for a deep copy of a string called source.

A: malloc(sizeof(char) * (strlen(source) + 1)) — the + 1 accounts for the null terminator.

Q: In the cleanUp function for book_t, why do you free sentences[sIndex] before freeing sentences itself?

A: Each sentences[sIndex] is a separately allocated string on the heap. If you free the sentences array first, you lose access to those inner pointers and can no longer free them, resulting in a memory leak.

Q: What does realloc(res, nG * sizeof(videogame_t)) do in the getClassicGames function?

A: It resizes the result array res from its initial over-allocation (size n) down to the actual number of matching games (nG), reclaiming the unused heap memory.

Q: Which of the following mechanisms stores related information of different data types together: Array, String, Struct, or all of these?

A: Struct. Arrays and strings store elements of the same type. Only structs combine different types under one name.


Connections to Other Topics

Structs with pointer members are the foundation of linked lists (each node is a struct containing data and a pointer to the next node). The malloc/free discipline practised here extends directly to trees, graphs, and any data structure built at runtime. The deep-copy pattern is also essential in any scenario where you need independent duplicates of complex data.


Related Terms / Search Tags

struct C, typedef struct, array of structs, dot operator, arrow operator, malloc, free, realloc, sizeof, dynamic memory allocation C, stack vs heap, deep copy C, shallow copy, memory deallocation, cleanUp function, book_t, videogame_t, C 101 UCF, Computer Science I