Skip to study material
← Question index

QUESTION 26 · Dynamic Memory

Explain uninitialised pointers, dangling pointers and memory leaks.

5 marks

Answer in brief

Pointer safety requires a valid target, correct bounds and a suitable lifetime. A pointer-looking value alone is not proof that access is allowed.

Uninitialised pointer

An ordinary automatic pointer declared without an initialiser does not contain a useful guaranteed pointer value. Do not read or dereference it. Initialise it to a valid address or a null pointer according to its intended state.

Dangling pointer

A pointer becomes unusable for target access when that object’s lifetime ends. Examples include a pointer to an automatic local array after its function returns and a pointer into a freed allocation. A non-null check does not establish that either target is still alive.

Memory leak

If the last useful pointer to an allocated block is lost before free, the program may no longer be able to release it. Overwriting p directly with a failed realloc result is a common source of this mistake. Use a temporary result for non-zero reallocation.

Out-of-bounds access

An index or pointer must remain within the appropriate object. A formed one-past-end pointer is not a valid element to dereference. String routines also require reachable termination and enough writable destination capacity. Merely changing a pointer’s type does not create a larger object.

Good practice

  1. State who owns each allocation and who must free it.
  2. Check allocation results and relevant input limits.
  3. Release the allocation exactly once; do not free an interior pointer.
  4. Clear a local pointer after free when it helps avoid later use, while remembering aliases remain invalid.
  5. Return pointers only to storage with a suitable remaining lifetime.

Key distinction

These are correctness rules, not optional optimisations. An invalid access has undefined behaviour; passing a small test does not make the access valid.

Worked example: resize an array without losing its original address

A student stores three marks in a dynamically allocated array and later needs room for five. A successful realloc may move the block. For a non-zero requested size, a failed realloc returns a null pointer and leaves the original block allocated.

↔ Scroll horizontally on a small screen
The two possible resize results
ResultWhat happens to the data?What should the program do?
SuccessThe first three integers are preserved; the added space is uninitialisedAssign the returned pointer to items, then initialise the two new elements
FailureThe original three-element block remains allocatedKeep its pointer for later use, or free it before returning

Common mistake

Writing items = realloc(items, ...) directly can overwrite the only useful pointer with a null pointer on failure. Save the result in a temporary pointer first. After success, use the returned pointer; any old aliases to the previous allocation must not be used, even if the returned address appears unchanged.

Complete C example

This example uses fixed sizes of three and five integers. It frees the original block if resizing fails because the program is about to exit.

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    int *items = malloc(3 * sizeof *items);
    if (items == NULL) {
        puts("Allocation failed");
        return 1;
    }
    for (int i = 0; i < 3; ++i) { items[i] = (i + 1) * 10; }
    printf("Before: %d %d %d\n", items[0], items[1], items[2]);

    int *temporary = realloc(items, 5 * sizeof *items);
    if (temporary == NULL) {
        /* The original block is still available through items. */
        free(items);
        puts("Resize failed");
        return 1;
    }
    items = temporary;
    items[3] = 40;
    items[4] = 50;
    printf("After: %d %d %d %d %d\n",
           items[0], items[1], items[2], items[3], items[4]);
    free(items);
    items = NULL;
    return 0;
}

Output when both allocations succeed

Before: 10 20 30
After: 10 20 30 40 50

The program writes elements 3 and 4 before reading them. Increasing capacity does not automatically give those new integers useful values. If a real program accepts a size from input, it must also check that the size multiplication fits in size_t before allocating.

Related exam questions

Related questions in the dynamic memory category from the supplied papers. The marks below are the printed allocations, including any combined subquestion.

  • September/October 2021 · Q8(b) · 8 marks

    Write a note on dynamic memory allocation.

    Paper P01 · page 1
  • March/April 2023 · Q1(h) · 3 marks

    Write the syntax of malloc().

    Paper P02 · page 1

View this category in the exam question bank →