Mastering Pointers in C: Visual Memory Allocation, Pointer Arithmetic & TU Board Exam Guide

Author: Bhuban Subedi | Subject: C Programming (CACS151) | Semester: First Semester


If there is one single topic in the Tribhuvan University (TU) BCA First Semester C Programming (CACS151) syllabus that strikes both fear and fascination into students, it is undoubtedly Pointers.

Every year during practical lab sessions and semester-end board examinations, I see students losing valuable 5-mark and 10-mark questions simply because they memorized the syntax *p and &x without understanding what is physically happening inside the computer’s RAM.

In this master guide, we are going to strip away the confusion. We will look at pointers through visual memory diagrams, explore pointer arithmetic, see how pointers interact with arrays and functions, and analyze frequently asked TU board exam questions.


1. What Exactly Is a Pointer? (The Real Mental Model)

When you declare a normal variable in C, like:

int age = 22;

The operating system allocates a specific chunk of memory in RAM (typically 4 bytes for an integer on modern 32/64-bit architectures). This memory cell has two distinct properties:
1. The Content (Value): The actual data stored inside (22).
2. The Address: The unique hexadecimal or integer physical location in memory where that value resides (for example, 0x7ffee4b2c1a8 or simplified as 2048).

A Pointer is simply a variable whose sole purpose is to hold the memory address of another variable.

       Variable: age                Pointer: ptr
      +---------------+           +---------------+
      |      22       |           |     2048      | ---> (Points to age's address)
      +---------------+           +---------------+
Address:    2048                  Address:  5000

The Two Essential Operators:

  • Address-of Operator (&): Retrieves the physical memory location of a variable.
  • Dereference / Indirection Operator (*): Accesses the actual value stored at the memory location pointed to by the pointer.

Quick Syntax Breakdown:

#include <stdio.h>

int main() {
    int rollNumber = 101;
    int *ptr; // Declaration of a pointer to an integer

    ptr = &rollNumber; // Store the address of rollNumber into ptr

    printf("Value of rollNumber: %d\n", rollNumber);
    printf("Address of rollNumber (&rollNumber): %p\n", (void*)&rollNumber);
    printf("Value stored in ptr (Address): %p\n", (void*)ptr);
    printf("Value accessed via pointer (*ptr): %d\n", *ptr);

    return 0;
}

Bhuban’s Pro Tip: Notice how * plays two completely different roles in C. During declaration (int *ptr;), the asterisk tells the compiler that ptr is a pointer variable. During execution (printf("%d", *ptr);), the asterisk acts as the dereferencing operator to fetch the value. Mixing these two up is the #1 reason for early compilation errors!


2. Pointer Arithmetic: How Incrementing Really Works

A classic TU viva question asks: “If int *p = 1000;, what is the value of p + 1?”

Most beginners answer 1001. That is wrong.

Pointer arithmetic is strictly scale-aware. When you add an integer n to a pointer, the compiler increments the address by n * sizeof(data_type).

Data Type sizeof(data_type) (Typical 32/64-bit) Initial Address ptr ptr + 1 Result ptr + 2 Result
char * 1 byte 3000 3001 3002
int * 4 bytes 3000 3004 3008
float * 4 bytes 3000 3004 3008
double * 8 bytes 3000 3008 3016

What Pointer Operations Are Allowed?

  1. Adding an integer to a pointer (p + i): Moves forward by i elements.
  2. Subtracting an integer from a pointer (p - i): Moves backward by i elements.
  3. Subtracting two pointers of the same type (p2 - p1): Yields the number of elements between them.
  4. Comparison (p1 == p2, p1 < p2): Valid when both pointers point to elements within the same contiguous array.

What is NOT Allowed: You cannot add two pointers (p1 + p2), multiply pointers, or divide pointers. Memory addresses are locations, and adding two physical addresses makes no mathematical or operational sense.


3. Pointers and Arrays: The Deep Connection

In C, an array name without an index acts as a constant pointer to its first element (index 0).

int marks[5] = {85, 90, 78, 92, 88};

Here, marks is internally equivalent to &marks[0].

This gives rise to the universal pointer-subscript equivalence:
$$\text{marks}[i] \iff *(\text{marks} + i)$$

Practical Code: Traversing an Array Using Pointers

#include <stdio.h>

int main() {
    int scores[5] = {75, 82, 90, 64, 88};
    int *ptr = scores; // points to &scores[0]

    printf("Accessing array elements using Pointer Arithmetic:\n");
    for (int i = 0; i < 5; i++) {
        printf("Element %d: Value = %d | Address = %p\n", i, *(ptr + i), (void*)(ptr + i));
    }

    return 0;
}

4. Passing Pointers to Functions: Call by Value vs Call by Reference

Tribhuvan University board exams love asking you to explain Call by Reference (Simulation) using a classic swap function.

Why Standard Call by Value Fails to Swap:

When you pass plain variables to a function, C creates a local copy on the call stack. Any modifications happen inside the local stack frame and vanish when the function returns.

The Correct Pointer-Based Implementation:

#include <stdio.h>

// Function prototype using pointer parameters
void swapValues(int *a, int *b) {
    int temp = *a; // Store the value at address 'a'
    *a = *b;       // Put value at address 'b' into address 'a'
    *b = temp;     // Put stored temp value into address 'b'
}

int main() {
    int num1 = 45, num2 = 90;

    printf("Before Swap: num1 = %d, num2 = %d\n", num1, num2);

    // Pass the memory addresses using '&'
    swapValues(&num1, &num2);

    printf("After Swap:  num1 = %d, num2 = %d\n", num1, num2);

    return 0;
}
Output:
Before Swap: num1 = 45, num2 = 90
After Swap:  num1 = 90, num2 = 45

5. Pointer to Pointer (Double Pointer **)

A pointer stores the address of a variable. A double pointer stores the address of another pointer.

       Variable: x               Pointer: p1               Double Pointer: p2
      +------------+            +------------+            +------------------+
      |     50     |            |    1000    |            |       2000       |
      +------------+            +------------+            +------------------+
Address:   1000         Address:     2000         Address:        3000

Demonstration:

#include <stdio.h>

int main() {
    int x = 50;
    int *p1 = &x;     // p1 holds address of x
    int **p2 = &p1;   // p2 holds address of p1

    printf("Direct value of x: %d\n", x);
    printf("Value via single pointer (*p1): %d\n", *p1);
    printf("Value via double pointer (**p2): %d\n", **p2);

    return 0;
}

Double pointers are fundamental in Semester 3 Data Structures when allocating 2D dynamic matrices or altering head pointers in Linked Lists.


6. Dangerous Traps: Dangling, Null, and Wild Pointers

In your practical exams and viva, external examiners love testing your awareness of memory safety bugs.

+-------------------+-------------------------------------------------------------------------+
| Pointer Type      | What It Means & Why It Is Dangerous                                     |
+-------------------+-------------------------------------------------------------------------+
| Wild Pointer      | A pointer that has been declared but not initialized to any address.    |
|                   | Contains random garbage memory; dereferencing it causes crashes.        |
+-------------------+-------------------------------------------------------------------------+
| NULL Pointer      | A pointer explicitly initialized to NULL (`int *p = NULL;`).            |
|                   | Safe because you can check `if (p != NULL)` before accessing memory.    |
+-------------------+-------------------------------------------------------------------------+
| Dangling Pointer  | Points to a memory location that has already been deallocated/freed.    |
|                   | Occurs after `free(ptr)` or when returning address of a local variable. |
+-------------------+-------------------------------------------------------------------------+

7. Solved TU Board Exam Question

Board Question:

“Write a C program using pointers and dynamic memory allocation to input ‘N’ integer elements into an array, find the maximum and minimum numbers, and calculate their average.” (TU BCA Board Exam – 10 Marks)

Solution:

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

void calculateStats(int *arr, int size, int *max, int *min, float *avg) {
    int sum = 0;
    *max = *arr; // Initialize with first element *(arr + 0)
    *min = *arr;

    for (int i = 0; i < size; i++) {
        int currentVal = *(arr + i);

        if (currentVal > *max) {
            *max = currentVal;
        }
        if (currentVal < *min) {
            *min = currentVal;
        }
        sum += currentVal;
    }

    *avg = (float)sum / size;
}

int main() {
    int n, maximum, minimum;
    float average;
    int *numbers;

    printf("Enter total number of elements (N): ");
    if (scanf("%d", &n) != 1 || n <= 0) {
        printf("Invalid array size!\n");
        return 1;
    }

    // Allocate dynamic memory
    numbers = (int*)malloc(n * sizeof(int));
    if (numbers == NULL) {
        printf("Error: Memory allocation failed!\n");
        return 1;
    }

    printf("Enter %d integers:\n", n);
    for (int i = 0; i < n; i++) {
        printf("Element [%d]: ", i + 1);
        scanf("%d", numbers + i); // (numbers + i) is the address
    }

    // Calculate using pointer function
    calculateStats(numbers, n, &maximum, &minimum, &average);

    printf("\n--- RESULTS ---\n");
    printf("Maximum Element: %d\n", maximum);
    printf("Minimum Element: %d\n", minimum);
    printf("Average Value:   %.2f\n", average);

    // Free allocated heap memory
    free(numbers);
    numbers = NULL; // Prevent dangling pointer

    return 0;
}

8. Summary & Key Takeaways for TU BCA Students

  1. A pointer is simply a memory holder: & extracts address, * extracts data at that address.
  2. Pointer arithmetic steps by data type size: p + 1 advances by sizeof(*p) bytes, not 1 byte.
  3. Arrays and pointers share a close relationship: arr[i] is syntactic sugar for *(arr + i).
  4. Always sanitize memory: After calling free(p), assign p = NULL; immediately to avoid dangling pointer vulnerabilities.

Frequently Asked Questions (FAQ)

Q1: What is the size of a pointer in C?

On modern 64-bit operating systems, all pointers (whether char*, int*, or double*) occupy 8 bytes because they store a 64-bit memory address. On 32-bit systems, pointers occupy 4 bytes.

Q2: What is a void pointer (void *)?

A void pointer is a generic pointer that has no associated data type. It can hold the address of any data type (int, float, struct) and is commonly returned by memory allocation functions like malloc() and calloc(). Before dereferencing a void pointer, it must be explicitly typecasted.

Q3: Can we return a pointer from a function in C?

Yes, but you must ensure that the pointer does not point to a local automatic variable allocated on the stack (which is destroyed after the function returns). You should only return pointers to static variables, global variables, or dynamically allocated memory on the heap.

LEAVE A REPLY

Please enter your comment!
Please enter your name here