← Back to quizzesFree quiz

Pointers and Dynamic Memory in C

Pointers are one of the most powerful features of the C programming language. They allow direct manipulation of memory addresses, enabling efficient data structures, dynamic memory…

10 questions~5 min
Pointers and Dynamic Memory in C — Qwi
0 / 10
Score: 0%
1

What is the effect of the statement `p = &x;` when `p` is declared as `int *p;` and `x` is an `int` variable?

2

Given `char *p = NULL;` what will happen if the program later executes `*p = 'A';` without allocating memory first?

3

In the function `void incrementer(int *x) { *x = *x + 1; }`, what is the value of `a` after calling `incrementer(&a);` if `a` was initially 5?

4

What does the expression `p+1` compute when `p` is a pointer to `long int` and `p` holds the address 1230?

5

After executing `free(p); p = NULL;`, which of the following statements is true?

6

Which of the following correctly allocates memory for an array of 10 integers and initializes all elements to zero?

7

What is the main risk of writing `p = realloc(p, new_size);` without using a temporary pointer?

8

When passing an array `int t[10];` to a function as `void foo(int *p)`, what does `p` actually point to inside the function?

9

Consider the code snippet: `int *p = malloc(sizeof(int)); *p = 5; free(p); *p = 10;`. What is the behavior of the last statement?

10

Which statement correctly describes the difference between `malloc` and `calloc`?

Understanding Pointers in C

Pointers are one of the most powerful features of the C programming language. They allow direct manipulation of memory addresses, enabling efficient data structures, dynamic memory management, and low‑level system programming. This module explains the fundamentals of pointers, how to use them safely, and the common pitfalls to avoid.

What Is a Pointer?

A pointer is a variable that stores the address of another variable. The type of the pointer indicates the type of data it points to, which determines how pointer arithmetic works.

  • Declaration: int *p; declares p as a pointer to an int.
  • Initialization: Using the address‑of operator (&) assigns the address of a variable to a pointer, e.g., p = &x;.
  • Dereferencing: The unary asterisk (*) retrieves the value stored at the address held by the pointer, e.g., *p = 10;.

Assigning an Address: p = &x;

When p is declared as int *p; and x is an int variable, the statement p = &x; makes p point to x. This means p now holds the memory address where x resides. The pointer does not store the value of x itself, nor does it become NULL unless explicitly set.

Correct answer from the quiz: p receives the memory address of x.

Dereferencing a Null Pointer

Consider the declaration char *p = NULL;. The pointer p does not point to any valid memory location. Attempting to write *p = 'A'; tries to store a character at address 0, which is undefined behavior. The operating system typically protects low memory addresses, so the program will likely crash (segmentation fault) or exhibit unpredictable results.

Key takeaway: Never dereference a null pointer. Always allocate memory or assign a valid address before using *p.

Passing Pointers to Functions

Functions can receive pointers as parameters, allowing them to modify the original variables. For example:

void incrementer(int *x) {
    *x = *x + 1;
}

If a is initially 5 and we call incrementer(&a);, the function receives the address of a. Inside the function, *x refers to a itself, so the statement increments its value to 6. After the call, a holds 6.

Correct answer from the quiz: 6.

Pointer Arithmetic

When you add an integer to a pointer, the result is the original address plus the integer multiplied by the size of the pointed‑to type. This is why p + 1 does not simply add one byte.

Example: If p is a long int * and holds the address 1230, then p + 1 points to 1230 + sizeof(long int). Assuming sizeof(long int) = 8 bytes, the new address is 1238.

Correct answer from the quiz: Address 1238 (adds sizeof(long int)).

Dynamic Memory Allocation

C provides three primary functions for managing heap memory:

  • malloc(size_t size) – allocates size bytes; contents are indeterminate.
  • calloc(size_t count, size_t size) – allocates count * size bytes and initializes them to zero.
  • realloc(void *ptr, size_t new_size) – changes the size of an existing block, possibly moving it.

When you are finished with a block, you must free it with free(void *ptr). After freeing, the pointer becomes a dangling reference unless you set it to NULL.

Freeing Memory Safely

After calling free(p);, the memory previously pointed to by p is returned to the system, but p still contains the old address. Setting p = NULL; immediately after freeing eliminates the risk of accidental dereferencing, because a null pointer is easy to test and will cause a clear runtime error if used.

Correct answer from the quiz: p is a null pointer and must not be dereferenced.

Allocating and Initializing an Array

To allocate memory for an array of ten int elements and ensure all elements start at zero, the most straightforward approach is to use calloc:

int *arr = calloc(10, sizeof(int));

calloc automatically zero‑initializes the allocated block. Using malloc would require an explicit loop or memset to achieve the same effect.

Correct answer from the quiz: int *arr = calloc(10, sizeof(int));.

Reallocating Without a Temporary Pointer

The realloc function may fail, returning NULL while leaving the original memory block untouched. If you write p = realloc(p, new_size); and realloc fails, you lose the original pointer value, creating a memory leak because you can no longer free the original block.

Best practice: use a temporary pointer.

int *tmp = realloc(p, new_size);
if (tmp) {
    p = tmp; // success
} else {
    // handle error, original p is still valid
}

Correct answer from the quiz: If realloc fails, the original pointer is lost causing a memory leak.

Arrays and Pointers in Function Parameters

When an array is passed to a function, it decays to a pointer to its first element. Therefore, the parameter int *p in void foo(int *p) points to t[0], the first element of the original array.

Correct answer from the quiz: The first element of the array.

Best Practices for Safe Pointer Usage

  • Initialize pointers to NULL when declared.
  • Check the result of malloc, calloc, and realloc before using the returned pointer.
  • Never dereference a null pointer; always ensure the pointer points to a valid memory block.
  • Free allocated memory when it is no longer needed, and set the pointer to NULL afterwards.
  • Use temporary pointers with realloc to avoid losing the original block on failure.
  • Prefer calloc when you need zero‑initialized memory.
  • Document ownership of dynamically allocated memory to avoid double frees or leaks.

Summary

This course covered the essential concepts of pointers and dynamic memory in C, including address assignment, dereferencing, pointer arithmetic, safe allocation, and deallocation. Mastery of these topics is crucial for writing robust, efficient C programs and for understanding how higher‑level languages manage memory under the hood.