-->

C Programming Day 9: Pointers in C | Address, Dereferencing & Examples

C Programming Day 9

C Programming Day 9 Pointers in C memory address and dereferencing tutorial


    Introduction

    Welcome to Day 9 of the C Programming Full Course.

    In Day 8, we learned about Functions in C, including function declarations, parameters, return values, prototypes, and recursion.

    Today, we are moving into one of the most important and powerful concepts in C programming:

    Pointers

    Pointers allow a program to work directly with memory addresses.

    At first, pointers can look confusing because they introduce concepts such as:

    • Memory addresses
    • Address-of operator &
    • Dereference operator *
    • Pointer variables
    • Pointers and arrays
    • Pointers and functions
    • Pointer arithmetic
    • Dynamic memory allocation
    • Arrays and strings
    • Structures
    • Data structures
    • Function arguments
    • File handling
    • System programming

    However, once you understand the relationship between a variable, its value, and its memory address, pointers become much easier.

    Pointers are especially important because they form the foundation for advanced C topics such as:

    So let's start from the fundamentals.


    What is a Pointer in C?

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

    For example:

    int number = 10;

    Here:

    • number stores the value 10.
    • The variable number also exists at a particular memory address.

    A pointer can store that address:

    int *ptr = &number;

    Conceptually:

    number
    |
    | value

    10

    ptr
    |
    | address of number

    number's memory location

    Therefore:

    *ptr

    contains the address of number.

    And:

    *ptr

    accesses the value stored at that address.


    Understanding Memory Addresses

    When a program runs, variables are stored somewhere in computer memory.

    For example:

    int number = 100;

    You can imagine the memory like this:

    Memory Address        Value
    0x1000                 100

    The actual address will vary between executions and systems.

    If number is stored at address 0x1000, then:

    &number

    represents that address.

    A pointer can store it:

    int *ptr = &number;

    Now:

    ptr → 0x1000

    and:

    *ptr → 100


    The Address-of Operator &

    The & operator is called the address-of operator.

    It returns the memory address of a variable.

    Example:

    #include <stdio.h>
    
    int main()
    {
        int number = 25;
    
        printf("Value = %d\n", number);
        printf("Address = %p\n", (void *)&number);
    
        return 0;
    }

    Example output:

    Value = 25
    Address = 0x7ffd12345678

    The exact address will normally be different on different executions.

    Important

    Use %p with a pointer value and convert to void * for portable printf usage:

    printf("%p", (void *)ptr);


    Declaring a Pointer

    The general syntax is:

    data_type *pointer_name;

    Examples:

    int *ptr;

    float *ptr;

    char *ptr;

    double *ptr;

    The pointer type should be compatible with the type of object whose address it points to.


    Assigning an Address to a Pointer

    Example:

    #include <stdio.h>
    
    int main()
    {
        int number = 50;
        int *ptr;
    
        ptr = &number;
    
        printf("Value = %d\n", number);
        printf("Address = %p\n", (void *)&number);
        printf("Pointer = %p\n", (void *)ptr);
    
        return 0;
    }

    The pointer now contains the address of number.


    Dereferencing a Pointer

    The * operator can be used to dereference a pointer.

    Dereferencing means accessing the value stored at the memory location held by the pointer.

    Example:

    #include <stdio.h>
    
    int main()
    {
        int number = 100;
        int *ptr = &number;
    
        printf("Value = %d\n", *ptr);
    
        return 0;
    }

    Output:

    Value = 100

    Here:

    ptr

    contains the address.

    While:

    *ptr

    accesses the value at that address.

    & vs *

    This is one of the most important things to understand.

    Operator  Meaning
    &variable             Gets the address of a variable
    *pointer             Gets the value stored at the pointer's address

    Example:

    int number = 10;
    int *ptr = &number;

    Then:

    number → 10
    &number → address of number
    ptr → address of number
    *ptr → 10

    A useful way to remember this is:

    & asks "Where is it?"
    * asks "What is stored there?"


    Complete Pointer Example

    #include <stdio.h>
    
    int main()
    {
        int number = 25;
        int *ptr = &number;
    
        printf("Value of number: %d\n", number);
        printf("Address of number: %p\n", (void *)&number);
        printf("Value stored in ptr: %p\n", (void *)ptr);
        printf("Value pointed to by ptr: %d\n", *ptr);
    
        return 0;
    }

    The important relationship is:

    number = 25
    
    &number
       ↓
    memory address
    
    ptr
       ↓
    same memory address
    
    *ptr
       ↓
    25


    Changing a Variable Through a Pointer

    One of the most useful features of pointers is that you can modify a variable through its pointer.

    Example:

    #include <stdio.h>
    
    int main()
    {
        int number = 10;
        int *ptr = &number;
    
        printf("Before: %d\n", number);
    
        *ptr = 50;
    
        printf("After: %d\n", number);
    
        return 0;
    }

    Output:

    Before: 10
    After: 50

    When you write:

    *ptr = 50;

    you change the value stored in number.


    Pointer and Data Types

    Pointer types should match the objects they point to.

    For example:

    int number = 10;
    int *ptr = &number;

    For a float:

    float price = 25.50f;
    float *ptr = &price;

    For a character:

    char letter = 'A';
    char *ptr = &letter;

    Using the correct pointer type is important because the compiler uses the type information when interpreting the pointed-to object and performing pointer arithmetic.


    Pointer to Pointer

    C also supports pointers that store the address of another pointer.

    Example:

    int number = 100;
    int *ptr = &number;
    int **pptr = &ptr;

    Conceptually:

    number
      ↑
     ptr
      ↑
    pptr

    Here:

    number

    stores 100.

    ptr

    stores the address of number.

    pptr

    stores the address of ptr.

    Therefore:

    *ptr

    gives:

    100

    And:

    **pptr

    also gives:

    100

    Example:

    #include <stdio.h>
    
    int main()
    {
        int number = 100;
    
        int *ptr = &number;
        int **pptr = &ptr;
    
        printf("%d\n", number);
        printf("%d\n", *ptr);
        printf("%d\n", **pptr);
    
        return 0;
    }

    Output:

    100
    100
    100


    Pointers and Arrays

    Pointers and arrays are closely related in C.

    Consider:

    int numbers[5] = {10, 20, 30, 40, 50};

    The array contains five elements.

    In most expressions, the array name can be converted to a pointer to its first element.

    So:

    numbers

    generally represents the address of:

    &numbers[0]

    For example:

    int *ptr = numbers;

    Now:

    *ptr

    accesses the first element.


    Accessing Array Elements Using a Pointer

    #include <stdio.h>
    
    int main()
    {
        int numbers[5] = {10, 20, 30, 40, 50};
    
        int *ptr = numbers;
    
        printf("%d\n", *ptr);
        printf("%d\n", *(ptr + 1));
        printf("%d\n", *(ptr + 2));
        printf("%d\n", *(ptr + 3));
        printf("%d\n", *(ptr + 4));
    
        return 0;
    }

    Output:

    10
    20
    30
    40
    50

    This demonstrates pointer arithmetic.

    Array Indexing and Pointer Notation

    These expressions are equivalent for an array numbers and valid index i:

    numbers[i]

    and:

    *(numbers + i)

    For example:

    numbers[2]

    is equivalent to:

    *(numbers + 2)

    This relationship is fundamental to understanding arrays and pointers in C.


    Pointer Arithmetic

    Suppose:

    int numbers[5] = {10, 20, 30, 40, 50};
    int *ptr = numbers;

    You can move the pointer:

    ptr++;

    Now the pointer points to the next int element.

    You can also write:

    ptr + 1

    or:

    ptr + 2

    Pointer arithmetic is scaled according to the size of the pointed-to type.

    For example, if ptr is an int *, then:

    ptr + 1

    points to the next int, not merely the next byte.


    Traversing an Array with a Pointer

    #include <stdio.h>
    
    int main()
    {
        int numbers[5] = {10, 20, 30, 40, 50};
        int *ptr = numbers;
        int i;
    
        for(i = 0; i < 5; i++)
        {
            printf("%d ", *(ptr + i));
        }
    
        return 0;
    }

    Output:

    10 20 30 40 50

    Pointer Increment Example

    #include <stdio.h>
    
    int main()
    {
        int numbers[5] = {10, 20, 30, 40, 50};
        int *ptr = numbers;
    
        printf("%d\n", *ptr);
    
        ptr++;
    
        printf("%d\n", *ptr);
    
        ptr++;
    
        printf("%d\n", *ptr);
    
        return 0;
    }

    Output:

    10
    20
    30

    Each increment moves the pointer to the next array element.


    Pointers and Functions

    Pointers become especially useful when working with functions.

    C passes function arguments by value. If you want a function to modify an existing variable in the caller, you can pass its address using a pointer.

    Example:

    #include <stdio.h>
    
    void changeValue(int *ptr)
    {
        *ptr = 100;
    }
    
    int main()
    {
        int number = 10;
    
        printf("Before: %d\n", number);
    
        changeValue(&number);
    
        printf("After: %d\n", number);
    
        return 0;
    }

    Output:

    Before: 10
    After: 100

    The function receives the address of number and modifies the original object through the pointer.


    Why Do We Use Pointers with Functions?

    Consider a normal function:

    void changeValue(int x)
    {
        x = 100;
    }

    Calling:

    int number = 10;
    
    changeValue(number);

    does not change the caller's number, because x receives a copy.

    With a pointer:

    void changeValue(int *x)
    {
        *x = 100;
    }

    calling:

    changeValue(&number);

    allows the function to modify the original variable.


    Practical Program: Swap Two Numbers Using Pointers

    One of the classic pointer programs is swapping two values.

    #include <stdio.h>
    
    void swap(int *a, int *b)
    {
        int temp;
    
        temp = *a;
        *a = *b;
        *b = temp;
    }
    
    int main()
    {
        int x = 10;
        int y = 20;
    
        printf("Before swap: x = %d, y = %d\n", x, y);
    
        swap(&x, &y);
    
        printf("After swap: x = %d, y = %d\n", x, y);
    
        return 0;
    }

    Output:

    Before swap: x = 10, y = 20
    After swap: x = 20, y = 10

    This is a very important example because it demonstrates how pointers allow a function to modify caller-owned variables.


    Practical Program: Find Array Sum Using Pointer

    #include <stdio.h>
    
    int arraySum(int *ptr, int size)
    {
        int sum = 0;
        int i;
    
        for(i = 0; i < size; i++)
        {
            sum += *(ptr + i);
        }
    
        return sum;
    }
    
    int main()
    {
        int numbers[] = {10, 20, 30, 40, 50};
    
        int sum = arraySum(numbers, 5);
    
        printf("Sum = %d", sum);
    
        return 0;
    }

    Output:

    Sum = 150


    Practical Program: Find Largest Element Using Pointer

    #include <stdio.h>
    
    int findLargest(int *ptr, int size)
    {
        int largest = ptr[0];
        int i;
    
        for(i = 1; i < size; i++)
        {
            if(*(ptr + i) > largest)
            {
                largest = *(ptr + i);
            }
        }
    
        return largest;
    }
    
    int main()
    {
        int numbers[] = {25, 80, 45, 90, 35};
    
        int largest = findLargest(numbers, 5);
    
        printf("Largest = %d", largest);
    
        return 0;
    }

    Output:

    Largest = 90


    Practical Program: Reverse an Array Using Pointers

    #include <stdio.h>
    
    void reverseArray(int *ptr, int size)
    {
        int i;
        int temp;
    
        for(i = 0; i < size / 2; i++)
        {
            temp = ptr[i];
            ptr[i] = ptr[size - 1 - i];
            ptr[size - 1 - i] = temp;
        }
    }
    
    int main()
    {
        int numbers[] = {10, 20, 30, 40, 50};
        int i;
    
        reverseArray(numbers, 5);
    
        printf("Reversed array:\n");
    
        for(i = 0; i < 5; i++)
        {
            printf("%d ", numbers[i]);
        }
    
        return 0;
    }

    Output:

    Reversed array:
    50 40 30 20 10


    Pointers and Strings

    Strings in C are character arrays.

    For example:

    char name[] = "JITU";

    A character pointer can point to the first character:

    char *ptr = name;

    Then:

    printf("%s", ptr);

    can print the string.

    Example:

    #include <stdio.h>
    
    int main()
    {
        char name[] = "JITU";
        char *ptr = name;
    
        printf("%s", ptr);
    
        return 0;
    }

    Output:

    JITU

    Important Difference: Character Array vs String Literal Pointer

    Consider:

    char name[] = "JITU";

    This creates a modifiable character array initialized with the string.

    By contrast:

    const char *name = "JITU";

    points to a string literal, which must not be modified through that pointer.

    Therefore, avoid code such as:

    char *name = "JITU";
    name[0] = 'X';

    because modifying a string literal results in undefined behavior.

    A safer form is:

    char name[] = "JITU";
    name[0] = 'X';


    NULL Pointers

    A NULL pointer is a pointer that intentionally does not point to a valid object.

    Example:

    int *ptr = NULL;

    You can test it:

    if(ptr == NULL)
    {
        printf("Pointer is NULL");
    }

    A NULL pointer should not be dereferenced.

    This is dangerous:

    *ptr = 10;

    if ptr is NULL.

    Uninitialized Pointers

    Never use an uninitialized pointer.

    Dangerous:

    int *ptr;
    
    *ptr = 10;

    The pointer does not yet contain a valid address to an object.

    A better approach is:

    int number;
    
    int *ptr = &number;
    
    *ptr = 10;

    Or initialize a pointer to NULL when it does not yet point to an object:

    int *ptr = NULL;

    Dangling Pointers

    A dangling pointer is a pointer that refers to an object whose lifetime has ended.

    For example, returning the address of a local automatic variable is invalid:

    int *getNumber()
    {
        int number = 10;
    
        return &number;
    }

    After the function returns, number no longer exists, so the returned pointer is invalid.

    This is an important memory-safety issue in C.

    Pointer Safety Rules

    When working with pointers:

    1. Initialize pointers before using them.
    2. Do not dereference NULL.
    3. Do not dereference an invalid pointer.
    4. Do not access memory outside an object's valid lifetime.
    5. Keep pointer types compatible with the objects they point to.
    6. Be careful with pointer arithmetic.
    7. Do not return pointers to expired local variables.
    8. Use const when a function should not modify pointed-to data.

    Using const with Pointers

    Suppose a function only needs to read an array and should not modify it.

    You can write:

    int arraySum(const int *ptr, int size)
    {
        int sum = 0;
    
        for(int i = 0; i < size; i++)
        {
            sum += ptr[i];
        }
    
        return sum;
    }

    The const tells the compiler that the function should not modify the elements through ptr.

    This improves clarity and helps prevent accidental modification.

    Pointer Arithmetic Rules

    Pointer arithmetic is not the same as ordinary integer arithmetic.

    For:

    int *ptr;

    these operations can be meaningful when ptr points within an array:

    ptr++;
    ptr--;
    ptr + 2;
    ptr - 2;

    Pointers can also be compared when they point into the same array object.

    However, pointer arithmetic should remain within the valid array/object boundaries. Going beyond the permitted range and dereferencing the result is undefined behavior.

    Pointer Size

    A pointer stores an address, and its size depends on the platform and pointer type.

    You can inspect it with:

    #include <stdio.h>
    
    int main()
    {
        int *ptr;
    
        printf("Pointer size = %zu bytes", sizeof(ptr));
    
        return 0;
    }

    On many modern 64-bit systems, object pointers are commonly 8 bytes, but you should not assume a particular size in portable C code.


    Pointer vs Normal Variable

    Normal Variable       Pointer
    Stores a value                         Stores an address
    Example: int x                         Example: int *p
    Access value directly                        Access pointed value using *p
    x gives value             p gives address
    &x gives address             *p gives pointed value

    Example:

    int x = 50;
    int *p = &x;

    Then:

    x     → 50
    &x    → address of x
    p     → address of x
    *p    → 50


    Real-World Applications of Pointers

    Pointers are used throughout C programming.

    Dynamic Memory

    Functions such as:

    malloc()
    calloc()
    realloc()
    free()

    use pointers to manage dynamically allocated memory.

    Dynamic memory allocation will be studied in a later lesson.

    Arrays

    Pointers provide another way to access and process array elements.

    Strings

    Character pointers are widely used for string processing.

    Functions

    Pointers allow functions to modify caller-owned data and are also used with function pointers.

    Structures

    Pointers to structures are heavily used in practical C programs.

    Data Structures

    Linked lists, trees, graphs, and other dynamic data structures rely heavily on pointers.

    System Programming

    Pointers are fundamental when working closely with memory, operating-system interfaces, and hardware-related programming.


    Common Pointer Mistakes

    Mistake 1: Dereferencing an Uninitialized Pointer

    Incorrect:

    int *ptr;
    
    printf("%d", *ptr);

    The pointer has not been given a valid address.

    Mistake 2: Dereferencing NULL

    Incorrect:

    int *ptr = NULL;
    
    printf("%d", *ptr);

    A NULL pointer must not be dereferenced.

    Mistake 3: Returning the Address of a Local Variable

    Incorrect:

    int *getValue()
    {
        int x = 10;
    
        return &x;
    }

    x ceases to exist when the function returns.

    Mistake 4: Going Outside an Array

    For:

    int numbers[5];

    valid element indexes are:

    0, 1, 2, 3, 4

    Do not dereference:

    numbers[5]

    Mistake 5: Confusing p and *p

    If:

    int *p;

    then:

    p

    is the pointer value/address it stores.

    While:

    *p

    is the object value accessed through that address.


    Best Practices for Pointers

    Initialize Pointers

    Prefer:

    int *ptr = NULL;

    until the pointer has a valid target.

    Use Meaningful Names

    For example:

    int *studentMarks;

    can be clearer than:

    int *p;

    in larger programs.

    Use const When Appropriate

    If a function only reads data:

    void display(const int *numbers, int size);

    Keep Pointer Lifetimes Clear

    Make sure the object a pointer refers to remains alive for as long as you need to use the pointer.

    Avoid Unnecessary Pointer Arithmetic

    Array indexing is often clearer:

    numbers[i]

    rather than:

    *(numbers + i)

    unless pointer notation helps explain or implement the operation.


    Interview Questions on Pointers in C

    1. What is a pointer?

    A pointer is an object that stores the address of another object or function, depending on the pointer type.

    2. What does & do?

    The & operator obtains the address of an object when used appropriately.

    3. What does * do with a pointer?

    The unary * operator dereferences a pointer, accessing the object it points to.

    4. What is a NULL pointer?

    A NULL pointer is a pointer value that indicates it does not currently point to a valid object.

    5. Why are pointers used with functions?

    Pointers allow functions to access or modify caller-owned objects and are also useful for passing arrays and other data structures.

    6. What is pointer arithmetic?

    Pointer arithmetic allows certain operations such as incrementing or decrementing a pointer within an array object.

    7. What is a dangling pointer?

    A dangling pointer refers to an object whose lifetime has ended or whose storage is otherwise no longer valid.

    8. What is a pointer to pointer?

    It is a pointer that stores the address of another pointer.

    Example:

    int **pptr;

    9. Are arrays and pointers exactly the same?

    No. Arrays and pointers are different C types. However, in many expressions, an array name is converted to a pointer to its first element.

    10. Why are pointers important in C?

    Pointers provide direct access to addresses and are fundamental for arrays, strings, dynamic memory, data structures, and many systems-level programming techniques.


    Practice Problems

    Beginner

    • Declare an integer variable and print its address.
    • Create a pointer to an integer.
    • Print a variable's value using a pointer.
    • Change a variable's value using a pointer.
    • Create a pointer to a float.
    • Create a pointer to a character.
    • Check whether a pointer is NULL.

    Intermediate

    • Print all array elements using a pointer.
    • Find the sum of an array using pointers.
    • Find the largest element using a pointer.
    • Find the smallest element using a pointer.
    • Reverse an array using pointers.
    • Swap two numbers using pointers.
    • Pass an array to a function using a pointer.
    • Create a function that modifies two variables using pointers.

    Advanced

    • Create a pointer-to-pointer example.
    • Reverse a string using pointers.
    • Count characters in a string using a pointer.
    • Compare two strings using pointers.
    • Create a calculator where operations are organized into functions.
    • Create an array-processing library using functions and pointers.
    • Explore dynamic memory allocation using malloc() and free().


    Conclusion

    Congratulations! 🎉 You have successfully completed C Programming Day 9 — Pointers in C.

    In this lesson, you learned how pointers work with memory addresses and values, including the address-of operator & and dereference operator *. You also explored pointer declaration, pointer initialization, pointer arithmetic, pointers with arrays and functions, pointer-to-pointer concepts, NULL pointers, and practical programs such as swapping values, finding array sums, and reversing arrays.

    Pointers are one of the most powerful concepts in C because they provide a foundation for advanced programming techniques such as dynamic memory allocation, structures, data structures, strings, and system-level programming.

    The most important concept to remember is:

    Variable → Stores a Value
    &Variable → Gives Its Address
    Pointer → Stores the Address
    *Pointer → Accesses the Value

    Don't worry if pointers seem challenging at first. The best way to master them is through regular coding practice and small programs. Start with simple variables, then move to arrays, functions, and more advanced pointer operations.

    In the next lesson, we'll continue our C programming journey with Structures and Unions in C, where you'll learn how to group different types of data together and build more organized, real-world programs.

    Keep practicing, keep coding, and keep learning C!


    Frequently Asked Questions (FAQ)

    Are pointers difficult to learn?
    Pointers can seem difficult initially because they introduce memory addresses and indirection. Start with simple examples involving one variable before moving to arrays and functions.
    What is the difference between & and *?
    & obtains an address, while unary * dereferences a pointer to access the pointed-to object.
    Can a pointer store an integer directly?
    A pointer is designed to store an address, not an ordinary integer value. Use an integer variable for integer data and a pointer to store the address of that variable.
    Can pointers be used with arrays?
    Yes. Pointers and arrays are closely related in C, and pointers are commonly used to traverse and process arrays.
    Can a function change a variable using a pointer?
    Yes. Passing the variable's address allows the function to modify the original object through the pointer.
    What should I learn after pointers?
    The next important topics include structures, unions, dynamic memory allocation, and file handling. These concepts build on your understanding of pointers.
    Why are pointers important in C?
    Pointers provide direct access to addresses and are fundamental for arrays, strings, dynamic memory, data structures, and many systems-level programming techniques.

    0/Post a Comment/Comments

    Thank You For Visit My Website.
    I Will Contact As Soon As Possible.