Skip to content

Chapter 1 of 7

Pointers and Dynamic Memory

Pointers are central to C, serving as variables that store the memory address of another value. They are declared with the star operator, as in int *ptr, and the address-of operator & produces a variable's address to assign to a pointer. Dereferencing with * accesses the value at the address a pointer holds. A NULL pointer is one that points to no valid memory location, and it is essential to check for NULL before dereferencing to avoid segmentation faults. Beyond ordinary pointers, C supports void pointers, which are generic and can point to any data type but require a cast before dereferencing, and double pointers, which store the address of another pointer and are useful for modifying a pointer inside a function or for arrays of strings like char **argv.

Pointer arithmetic automatically scales by the size of the pointed-to type. Incrementing an int * advances by sizeof(int) bytes rather than by one, which is why expressions like *(p + i) work correctly for any array regardless of element size. Subtracting two pointers yields the number of elements between them, not the raw byte difference. The const keyword has different effects depending on placement: const int *p means the value cannot be changed through p, int *const p means p itself cannot be reassigned, and const int *const p locks down both. The sizeof operator returns the size in bytes of a type or variable at compile time, and the idiom sizeof(arr) / sizeof(arr[0]) recovers an array's length; for pointers, however, sizeof returns the pointer size rather than the size of the pointed-to data.

C manages memory in two main regions: the stack, which automatically holds local variables and is fast but limited, and the heap, which is larger but requires manual management. malloc(size) allocates uninitialized memory on the heap and returns NULL on failure, while calloc(count, size) zero-initializes all bytes and additionally checks for overflow in count * size, making it safer than computing that product yourself. realloc(ptr, new_size) resizes an existing allocation and may relocate it, so its result should always be assigned to a temporary pointer to avoid losing the original block on failure. Every dynamically allocated block must be released with free; forgetting causes a memory leak, and after freeing you should set the pointer to NULL to prevent a dangling pointer from causing undefined behavior on later use. Tools like Valgrind help detect leaks during development.

All chapters
  1. 1Pointers and Dynamic Memory
  2. 2Data Types, Variables, and User-Defined Aggregates
  3. 3Arrays, Strings, and Memory Operations
  4. 4Functions and Control Flow
  5. 5File I/O and Program Termination
  6. 6The Preprocessor and Macros
  7. 7Compilation, Linking, and Program Structure

Drill it

Reading is not remembering. These come from the C Programming deck:

Q

What is a pointer in C?

A pointer is a variable that stores the memory address of another variable.Declared using the * operator: int *ptr;The address-of operator & retrieves a var...

Q

How do you dereference a pointer?

Dereferencing means accessing the value stored at the address a pointer holds.Use the * operator: int val = *ptr;This retrieves the value at the memory location...

Q

What is a NULL pointer?

A NULL pointer is a pointer that does not point to any valid memory location.Assigned with: int *ptr = NULL;Always check for NULL before dereferencing to avoid...

Q

What does malloc() do in C?

malloc() allocates a block of memory on the heap and returns a pointer to it.Syntax: int *p = (int *)malloc(n * sizeof(int));Returns NULL if allocation fails. M...