L14: Pointers

Pointers #


๐Ÿงฉ What is a Pointer? #

A pointer is a variable that stores the memory address of another variable.

int x = 10;
int *p = &x; // p stores address of x
printf("%d", *p); // prints 10
  • &x gives the address of x.
  • *p gives the value stored at that address.

๐Ÿงฎ Memory Visualization #

VariableAddressValue
x100010
p20001000

*p โ†’ value at address 1000 โ†’ 10


๐Ÿง  Example 1: Swapping Two Numbers #

โŒ Without Pointers #

void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

a and b are copies of the arguments. The swap doesnโ€™t affect the original numbers.

โœ… With Pointers #

void swap(int *a, int *b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}
int x = 5, y = 10;
swap(&x, &y);
printf("%d %d", x, y); // 10 5 โœ…

๐Ÿ“ˆ Runtime & Memory Advantage

  • Only addresses passed โ†’ small data movement.
  • No extra copies.

Example 2: Passing Arrays to Functions #

Arrays are automatically passed by reference (address).

void doubleArray(int *arr, int n) {
    for (int i = 0; i < n; i++)
        arr[i] *= 2;
}

int main() {
    int arr[] = {1, 2, 3};
    doubleArray(arr, 3);
}

โœ… Works directly on the original array.
โœ… No duplication โ€” only base address passed.


Example 3: Returning Multiple Values #

Without pointers โ†’ only one return value possible.

โœ… Using pointers:

void compute(int a, int b, int *sum, int *prod) {
    *sum = a + b;
    *prod = a * b;
}
int s, p;
compute(5, 10, &s, &p);
printf("Sum=%d Product=%d", s, p);

Null Pointer? #

int *ptr = NULL;
  • A null pointer is a pointer that points to nothing โ€” i.e., memory address 0.
  • Itโ€™s a sentinel value used to indicate that the pointer isnโ€™t initialized or points to no valid object.
  • Trying to dereference a null pointer causes a runtime error.

โœ… Use case:
Initialize pointers to NULL to avoid undefined behavior when checking their validity later.


โš ๏ธ Slide 2: Common Mistake โ€” Dereferencing NULL #

int *p = NULL;
printf("%d", *p);  // โŒ Segmentation Fault
  • Dereferencing a null pointer leads to a segmentation fault (SIGSEGV).
  • The operating system prevents access to memory address 0x0.
  • Such crashes are common in unsafe pointer operations.

โœ… Best practice:
Always check before dereferencing:

if (p != NULL)
    printf("%d", *p);

๐Ÿ’ฅ Slide 3: Segmentation Faults #

A segmentation fault occurs when a program tries to access restricted or invalid memory.

Common Causes: #

  1. Dereferencing a NULL pointer
  2. Using an uninitialized pointer
  3. Accessing freed memory
  4. Writing out of bounds of an array

๐Ÿงจ Slide 4: Example โ€” Uninitialized Pointer #

int *p;     // Not initialized
*p = 5;     // โŒ Undefined behavior โ€” random memory location
  • The pointer contains garbage value.
  • Program may crash or corrupt memory.

โœ… Always initialize pointers:

int *p = NULL;

๐Ÿ” Slide 5: Security Bugs due to Bad Pointers #

TypeDescriptionExample
Use-after-freeAccessing memory after itโ€™s freedFreeing pointer but still dereferencing
Buffer overflowWriting outside array boundsWriting past array end corrupts memory
Dangling pointerPointer to freed/deleted objectForgetting to set pointer to NULL after free()

Pointer Arithmetic #


๐Ÿงฉ 1. Pointer Arithmetic #

๐Ÿ“˜ Basic Rules #

If p is a pointer to an element of an array, then:

  • p + 1 points to the next element.
  • p - 1 points to the previous element.
  • Difference of pointers gives the number of elements between them.

๐Ÿงฎ Example #

#include <stdio.h>
int main() {
    int arr[] = {10, 20, 30, 40};
    int *p = arr;
    printf("%d\n", *(p + 2)); // prints 30
    printf("%ld\n", (p + 3) - p); // prints 3
    return 0;
}

๐Ÿงฎ 2. Pointer Arithmetic on Arrays #

You can iterate through arrays using pointers.

#include <stdio.h>
int main() {
    int arr[] = {1, 2, 3, 4, 5};
    int *ptr = arr;

    for(int i = 0; i < 5; i++)
        printf("%d ", *(ptr + i)); // pointer arithmetic
}

โœ… Saves overhead of indexing, especially in performance-critical loops.


Based on the pointer type, addresses are incremented by appropriate sizes:

#include <stdio.h>
int main() {
  long long x[] = {1,2,3,4,5,6};
  long long* p = x;
  printf("%d\n", sizeof(x[0]));
  int y = p+1;
  char* pc = x;  
  printf("%d %d %d %d\n",p, y, pc, pc+1);
  return 0;
}

For a char pointer +1, increments address by 1 and for long long increments by 8!


๐Ÿงญ 3. Pointer Casting #

You can cast one pointer type to another, but must be careful with alignment and type sizes.

โš™๏ธ Example: Casting between int* and char* #

#include <stdio.h>
int main() {
    int x = 0x12345678;
    char *p = (char*)&x;
    printf("First byte: %x\n", *p); // prints 78 on little-endian
}

๐Ÿง  Use case: Byte-level manipulation, file I/O, or network communication.