๐Ÿ‘‰ Topic 13 โ€” Pointers

A pointer lets a program work with an object through its address. Instead of storing a value such as 25, a pointer stores the address of an object.

You will use pointers to update values in a calling function, visit array elements, process strings, and use dynamically allocated storage.

Why this topic matters: Start by separating a value from its address. Then follow how a pointer stores the address and how dereferencing uses it to reach the original object.

13.1 What Is a Pointer?

A pointer variable stores a pointer value. It can point to an object of a suitable type, point to a function when declared as a function pointer, or hold a null pointer value.

Consider:

int age = 20;

The variable age stores the value 20. The computer also associates age with a memory location. A pointer can store that memory address.

int age = 20; int *ptr = &age;

Here:

  • age stores 20.
  • &age produces the address of age.
  • ptr stores that address.
  • *ptr accesses the object stored at that address.
 Variable โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” age โ”‚ 20 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ–ฒ โ”‚ โ”‚ address of age โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” ptr โ”‚ &age โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ *ptr โ†’ 20 

13.2 Why Do We Need Pointers?

1. Access Memory Indirectly

A pointer allows a program to reach an object through its address.

2. Modify Caller Data

A pointer can be passed to a function so the function can modify an object belonging to the caller.

3. Work with Arrays

Arrays and pointers are closely related in C expressions and function calls.

4. Work with Strings

Character pointers are commonly used to process C strings.

5. Dynamic Memory

Functions such as malloc() and free() use pointers.

6. Advanced C

Structures, linked lists, trees, function pointers and system programming all depend heavily on pointer concepts.

13.3 The Two Most Important Pointer Operators

Operator Name Meaning Example
& Address-of Produces the address of an object &number
* Indirection / Dereference Accesses the object referred to by a pointer *ptr
Important: The same symbols can have different meanings depending on context. For example, * can mean multiplication in a * b, but dereference a pointer in *ptr. Similarly, & can mean address-of in &x, while it can mean bitwise AND in a & b.

13.4 Declaring a Pointer

The basic syntax is:

data_type *pointer_name;

Examples:

int *p; float *pricePtr; char *letterPtr; double *valuePtr;

The type tells the compiler what kind of object the pointer is intended to point to.

Remember: The declaration int *p; means that p has pointer type capable of pointing to an int object. It does not mean that p itself is an integer variable.

13.5 Understanding int *p

Beginners often read:

int *p;

as:

"p is an integer."

That is incorrect.

The correct interpretation is:

p is a pointer to an int.

 int number = 50; int *p = &number; number โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ 50 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ–ฒ โ”‚ โ”‚ โ”‚ points to โ”‚ p โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ address โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ 

13.6 Address-of Operator &

The address-of operator obtains the address of an object.

int number = 25; printf("%p\n", (void *)&number);

The printed address can change between runs and systems. Learn the relationship between the variable and pointer rather than memorizing an address shown in one run.

For printing a pointer value with printf, use %p and convert the pointer to void *:
printf("%p\n", (void *)ptr);

13.7 Dereference Operator *

The dereference operator accesses the object referred to by a valid pointer.

int number = 25; int *ptr = &number; printf("%d\n", *ptr);

Output:

25

The expression *ptr means:

"Access the object that ptr points to."

13.8 Reading and Modifying Through a Pointer

If ptr points to a writable variable, assigning to *ptr changes that variable. The pointer still holds the same address; the value at the target changes.

#include <stdio.h>

int main(void) {
    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

Why did number change? Because *ptr refers to the same object as number.

13.9 Pointer Program Tracing

Trace: number and ptr
int number = 10; int *ptr = &number; *ptr = 50;
Step Statement number ptr *ptr
1 int number = 10; 10 Not created yet โ€”
2 int *ptr; 10 Uninitialized Do not dereference
3 ptr = &number; 10 Address of number 10
4 *ptr = 50; 50 Same address 50
 points to ptr โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ number โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ 50 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ *ptr means: "Go to the object at ptr's address." 

13.10 Pointer and Pointee

The object whose address is stored in a pointer is often called the pointee.

int x = 100; int *p = &x;

Here:

  • p is the pointer.
  • x is the pointee.
  • &x is the address stored in p.
  • *p accesses x.

13.11 Pointer Initialization

Give a pointer a valid value before using it. To dereference it, it must point to an existing object that can be accessed with the pointed-to type.

int value = 40; int *p = &value;

A pointer can also intentionally contain a null pointer value:

int *p = NULL;

A null pointer means that no object or function is selected. It is useful as a starting value when the program does not have a target yet.

Never dereference a null pointer. An expression such as *p is invalid when p == NULL.

13.12 NULL Pointer

A null pointer is a pointer value that compares unequal to a pointer to any object or function.

int *ptr = NULL; if (ptr == NULL) { printf("Pointer is NULL\n"); }

Modern C code may use nullptr in C23, but many educational and existing C programs use NULL. The important concept is that the pointer must not be dereferenced while it is null.

13.13 Uninitialized Pointers

This is dangerous:

int *p; *p = 10;

Declaring the pointer does not create a target object or give it a target address. Dereferencing this uninitialized pointer has undefined behavior. Assign a valid address before using it.

Use:

int value = 10; int *p = &value;

or, when there is no target yet:

int *p = NULL;

13.14 Pointer Types

Pointer Can point to
int * int object
char * char object
float * float object
double * double object
struct Student * struct Student object

The pointed-to type tells C what kind of object is being accessed. It also sets the element size used for pointer arithmetic.

13.15 Why Pointer Type Matters

Suppose:

int *p;

When *p is evaluated, the compiler interprets the object using the pointed-to type int.

For an int pointer into an array, adding 1 moves by one int element. It does not add one byte unless the pointed-to type has size one byte.

A common misconception is: "All pointers are exactly the same because they store addresses." Do not assume that every pointer has the same size or can access every object. A cast changes a pointer type; it does not make an incompatible object safe to access through that type.

13.16 Pointer Size vs Pointed-to Object Size

Do not assume that the size of a pointer is the size of the object it points to.

int x = 10; int *p = &x; printf("%zu\n", sizeof(x)); printf("%zu\n", sizeof(p));

Use sizeof to ask about each type separately. For example, an int pointer and an int may occupy different numbers of bytes on your system.

13.17 Pointers and Functions

The function receives a copy of the pointer value. That copy points to the same caller object. Writing through the copied pointer can change the callerโ€™s object; reassigning the local pointer does not reassign the callerโ€™s pointer.

Example:

#include <stdio.h>

void changeValue(int *p) {
    *p = 100;
}
int main(void) {
    int number = 20;
    changeValue(&number);
    printf("%d\n", number);
    return 0;
}

Output:

100

The pointer itself is passed by value, but the copied pointer points to the same number object.

13.18 Program Tracing โ€” Function + Pointer

 main() โ”‚ โ”‚ number = 20 โ”‚ โ”‚ changeValue(&number) โ–ผ changeValue(int *p) โ”‚ โ”‚ p receives a copy of number's address โ”‚ โ”‚ *p = 100 โ–ผ number becomes 100 โ”‚ โ–ผ return to main() 
Stage number p
Before function call 20 โ€”
Inside function 20 Address of number
After *p = 100 100 Address of number
After return 100 Function's local pointer no longer exists

13.19 Swapping Two Numbers Using Pointers

A classic pointer application is swapping two objects inside a function.

#include <stdio.h>

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

Output:

Before: 10 20 After: 20 10
The function does not receive x and y directly. It receives their addresses, allowing it to access and modify the original objects.

13.20 Pointer Arithmetic

Starting from an array element, pointer addition or subtraction must stay within that array or reach exactly one position past its end. Forming a pointer farther outside the array is not valid.

For example:

int numbers[] = {10, 20, 30, 40}; int *p = numbers; printf("%d\n", *p); printf("%d\n", *(p + 1)); printf("%d\n", *(p + 2));

Output:

10 20 30

The expression p + 1 does not mean "add one byte." It advances to the next int element.

13.21 Pointer Arithmetic and Array Elements

 int numbers[] = {10, 20, 30, 40}; Index: 0 1 2 3 โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ–ผ โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ” โ”‚ 10 โ”‚ โ”‚ 20 โ”‚ โ”‚ 30 โ”‚ โ”‚ 40 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”˜ โ–ฒ โ”‚ p p + 1 โ†’ points to element 1 p + 2 โ†’ points to element 2 

The exact byte distance depends on sizeof(int), but C pointer arithmetic automatically scales by the size of the pointed-to type.

13.22 Incrementing a Pointer

int numbers[] = {10, 20, 30}; int *p = numbers; printf("%d\n", *p); p++; printf("%d\n", *p);

Output:

10 20

After p++, the pointer refers to the next array element.

13.23 Pointer Subtraction

Subtract pointers within the same array to find the distance in elements. For example, &a[4] - &a[1] gives 3, not the distance in bytes.

int numbers[] = {10, 20, 30, 40, 50}; int *p1 = &numbers[1]; int *p2 = &numbers[4]; printf("%td\n", p2 - p1);

Output:

3

The result type is ptrdiff_t, for which %td is the appropriate printf conversion.

Both pointers must refer to the same array or its one-past position, and the difference must fit ptrdiff_t. Do not subtract pointers to unrelated objects.

13.24 One-Past-the-End Pointer

One position past the last element is a valid boundary pointer. Use it to stop a loop, but do not read or write through it. For five elements, a + 5 is the boundary; *(a + 5) is not an element.

int numbers[] = {10, 20, 30}; int *p = numbers; int *end = numbers + 3; while (p != end) { printf("%d\n", *p); p++; }

Here end is valid as a pointer value for the iteration boundary, but *end must not be evaluated.

13.25 Pointers and Arrays

An array expression often converts to a pointer to its first element when used in most expressions.

int numbers[] = {10, 20, 30}; int *p = numbers;

Here p points to numbers[0].

Therefore:

numbers[0] *(numbers + 0) numbers[1] *(numbers + 1) numbers[2] *(numbers + 2)

refer to corresponding elements.

Arrays are not pointers. For example, sizeof an actual array includes all its elements, while sizeof a pointer measures only that pointer. The common array-to-pointer conversion does not make these objects the same.

13.26 Array Indexing Is Related to Pointer Arithmetic

For an array or pointer expression, the notation:

a[i]

is defined in terms of pointer arithmetic as:

*(a + i)

For example:

int a[] = {5, 10, 15}; printf("%d\n", a[1]); printf("%d\n", *(a + 1));

Both print:

10

13.27 Pointers as Function Parameters for Arrays

When an array is used as a function argument, it normally converts to a pointer to its first element. In the functionโ€™s parameter list, an array-style declaration is adjusted to a pointer declaration.

#include <stdio.h>

void printArray(int a[], int n) {
    for (int i = 0; i < n; i++) {
        printf("%d ", a[i]);
    }
}
int main(void) {
    int numbers[] = {
        10, 20, 30, 40
    };
    printArray(numbers, 4);
    return 0;
}

Output:

10 20 30 40
The pointer does not tell the function how many elements are available. Pass the count as another argument and stay within that count. The elements remain in the callerโ€™s original array.

13.28 Important Interview Point: sizeof and Array Parameters

Consider:

void showSize(int a[]) { printf("%zu\n", sizeof(a)); }

Inside this parameter declaration, a is adjusted to a pointer parameter. Therefore sizeof(a) gives the size of the pointer, not the size of the original array.

This is why a function commonly receives the array length separately:

void process(int a[], int n)

13.29 Pointers and Strings

A C string is an array of characters terminated by a null character '\0'. A pointer can point to its first character.

char name[] = "Bhavya"; char *p = name; printf("%s\n", p);

Output:

Bhavya

The pointer can also be used to traverse the characters:

while (*p != '\0') { putchar(*p); p++; }

13.30 Character Pointer vs Character Array

Declaration Meaning
char text[] = "Hello"; Creates a modifiable character array initialized from the string literal.
char *p = text; Pointer points to the first character of the array.

Be careful with:

char *p = "Hello";

The string literal should not be modified through p. Use const char *p = "Hello" to show that the literal must not be changed through p. Use char text[] = "Hello" when you need a separate writable array.

13.31 Pointer to Pointer

A pointer variable is an object too, so it has an address. A pointer-to-pointer stores that address. One dereference reaches the pointer; a second reaches its target object.

int value = 25; int *p = &value; int **pp = &p;
 pp โ”‚ โ”‚ points to โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ p โ”‚ โ”‚ address of โ”‚ โ”‚ value โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ points to โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ value โ”‚ โ”‚ 25 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ *pp โ†’ p **pp โ†’ value โ†’ 25 

13.32 Dereferencing Multiple Levels

int value = 25; int *p = &value; int **pp = &p; printf("%d\n", **pp);

Output:

25

Explanation:

  1. pp points to p.
  2. *pp gives p.
  3. **pp accesses the object pointed to by p.

13.33 Const and Pointers

The const qualifier can be combined with pointer declarations in several different ways.

Pointer to const data

const int *p;

The object should not be modified through p. The pointer itself may be changed to point elsewhere.

Const pointer

int *const p = &value;

The pointer itself cannot be changed to point elsewhere after initialization, but the pointed-to int can be modified through p.

Const pointer to const data

const int *const p = &value;

Neither the pointer itself nor the object can be modified through that pointer.

13.34 Pointer Compatibility

Pointer types should be used carefully. For example:

int *p; double *q;

These pointers refer to different object types. Changing the pointer type with a cast is not enough to justify reading an int object as a float object. Access an object through a type that C permits.

The special pointer type void * can hold the address of an object of any object type and is widely used in generic C interfaces.

13.35 Void Pointers

int number = 50; void *ptr = &number;

A void * is a generic object pointer. Before dereferencing it, convert it to an appropriate pointer type or assign it to one.

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

The compiler cannot directly determine the pointed-to object type from void * alone.

Do not use void * unless the function is meant to accept different object types. The program must still know the actual target type before accessing the stored object.

13.36 Pointer Comparisons

Within the same array, relational comparisons such as p < end can show which position comes earlier. Do not use them to order unrelated allocated objects. Equality tests also let you check a pointer against NULL.

int a[] = {10, 20, 30}; int *p = &a[0]; int *q = &a[2]; if (p < q) { printf("p comes before q\n"); }

Equality and inequality comparisons are also commonly used when checking for null pointers:

if (p == NULL) { printf("No object\n"); }

13.37 Pointer Safety

Many serious C bugs involve invalid pointers.

Null Pointer

Do not dereference a null pointer.

Dangling Pointer

Do not use a pointer after the object it referred to has ceased to exist.

Uninitialized Pointer

Initialize pointers before using them.

Out-of-Bounds Pointer

Do not access outside the valid array/object boundaries.

Wrong Pointer Type

Use compatible pointer types and conversions.

String Literal Modification

Never modify a string literal through a pointer.

13.38 Dangling Pointers

A dangling pointer no longer gives valid access to its former target because the targetโ€™s lifetime has ended.

For example, returning the address of an ordinary local variable from a function is invalid:

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

When the function returns, the lifetime of the local object x has ended. The returned pointer cannot safely be dereferenced.

An address shown in a debugger does not prove that an object still exists. After the targetโ€™s lifetime ends, stop using pointer copies that referred to it. Return a value, use caller-provided storage, or allocate storage with a suitable lifetime instead.

13.39 Common Pointer Mistakes

Mistake Problem
Dereferencing an uninitialized pointer Undefined behavior
Dereferencing NULL Invalid access
Accessing outside an array Undefined behavior
Using a pointer after object lifetime ends Dangling pointer / invalid access
Returning address of local automatic variable Pointer becomes invalid after function returns
Writing through a pointer to read-only data Invalid modification

13.40 Pointer vs Value

Expression Meaning
x The value stored in object x
&x Address of object x
p Address stored in pointer p
*p Object accessed through pointer p

13.41 Pointer Visualization

 int marks = 85; int *p = &marks; stores 85 โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” marks โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ 85 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ–ฒ โ”‚ โ”‚ address โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” p โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บโ”‚ &marks โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ p = address of marks *p = 85 &marks = same address stored in p 
The pointer does not contain the value 85. It contains the address used to reach the object containing 85.

13.42 Complete Program Analysis

#include <stdio.h>

void update(int *p) {
    *p = *p + 10;
}
int main(void) {
    int marks = 70;
    int *ptr = &marks;
    printf("Before = %d\n", marks);
    update(ptr);
    printf("After = %d\n", marks);
    return 0;
}

Step 1 โ€” Create the variable

int marks = 70;

An integer object named marks is initialized with 70.

Step 2 โ€” Store its address

int *ptr = &marks;

ptr stores the address of marks.

Step 3 โ€” Call the function

update(ptr);

A copy of the pointer value is passed to update.

Step 4 โ€” Dereference

*p = *p + 10;

The function reads the caller's marks object through the pointer and changes it from 70 to 80.

Step 5 โ€” Return to main

The updated value remains in marks.

Output:

Before = 70 After = 80

13.43 Pointers and Memory Layout โ€” Conceptual View

The following is a conceptual model rather than a promise about exact addresses or physical memory organization.

 Object Pointer โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ value โ”‚โ—„โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”‚ address โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ–ฒ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ *p โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ 

Read the diagram as a relationship: the pointer identifies the object, and dereferencing reaches that object. The sample address is only a label for the explanation.

13.44 Pointers and sizeof

Remember that sizeof measures its operandโ€™s type or object size. Applying it to a pointer does not report how many elements are in an allocation reached through that pointer.

int x = 10; int *p = &x; printf("%zu\n", sizeof(x)); printf("%zu\n", sizeof(p)); printf("%zu\n", sizeof(*p));

The third expression, sizeof(*p), corresponds to the size of the pointed-to type, int, without requiring the pointed-to object's value to be read.

13.45 Pointer Expressions to Remember

Expression Meaning
p Pointer value
*p Object pointed to by p
&x Address of x
p + 1 Next element for an appropriate array pointer
p - 1 Previous element for an appropriate array pointer
p == NULL Check whether pointer is null
**pp Dereference a pointer-to-pointer twice

13.46 Common Confusions

Confusion 1 โ€” Pointer vs Address

&x is an expression that produces an address. A pointer object such as p stores a pointer value.

Confusion 2 โ€” *p vs p

p is the pointer value. *p accesses the object referred to by that pointer.

Confusion 3 โ€” Array vs Pointer

An array is not a pointer. An array expression commonly converts to a pointer to its first element in expressions.

Confusion 4 โ€” C Pass-by-Reference

C has pass-by-value. Passing a pointer allows the function to access the same caller object, which provides reference-like behavior without changing C's parameter passing rule.

13.47 Pointer to Array vs Array of Pointers

Read int *items[3] as three pointer elements, each able to point to an int. Read int (*row)[3] as one pointer to a whole three-int array. The parentheses change which part of the declaration belongs together.

Complete C program:

#include <stdio.h>

int main(void)
{
    int values[3] = {10, 20, 30};
    int *items[3] = {&values[0], &values[1], &values[2]};
    int (*row)[3] = &values;
    printf("Pointers: %d %d %d\n", *items[0], *items[1], *items[2]);
    printf("Array pointer: %d\n", (*row)[1]);
    return 0;
}

Expected output:

Pointers: 10 20 30
Array pointer: 20

Step-by-step explanation:

  1. Each items[i] points to one integer element.
  2. row points to the whole three-element array.
  3. Dereference row first, then index: (*row)[1].
Remember: With row + 1, pointer arithmetic moves by sizeof(values), not by sizeof(int).

13.48 const with Pointers โ€” Read Declarations Correctly

In const int *p, p may point elsewhere, but *p cannot be assigned through p. In int *const p, p must keep its initial target, but *p can change if the target is writable. const int *const p applies both restrictions.

Complete C program:

#include <stdio.h>

int main(void)
{
    int a = 5, b = 9;
    const int *readOnlyView = &a;
    printf("Before: %d\n", *readOnlyView);
    readOnlyView = &b;
    printf("After reseating: %d\n", *readOnlyView);
    return 0;
}

Expected output:

Before: 5
After reseating: 9

Step-by-step explanation:

  1. The pointer initially refers to a.
  2. Changing *readOnlyView is prohibited, but changing the pointer is allowed.
  3. After reassignment it refers to b.
Remember: Do not remove const through a cast and attempt to modify an object defined const; such modification is undefined behavior.

13.49 Quick Revision

๐Ÿ“Œ Pointer โ†’ stores an address.

๐Ÿ“Œ &x โ†’ address of x.

๐Ÿ“Œ *p โ†’ value at address stored in p.

๐Ÿ“Œ Pointer arithmetic is commonly used with arrays.

๐Ÿ“Œ Arrays and pointers are closely related, but they are not identical concepts.

๐Ÿ“Œ Pointers allow functions to modify caller data when addresses are passed.

๐Ÿ“Œ malloc() โ†’ dynamic allocation.

๐Ÿ“Œ calloc() โ†’ zero-initialized allocation.

๐Ÿ“Œ realloc() โ†’ resize allocation.

๐Ÿ“Œ free() โ†’ release allocation.

๐Ÿ“Œ NULL pointer โ†’ intentionally points to no valid object.
INTERACTIVE LEARNING

๐ŸŽฌ Pointers โ€” Address and Dereference Flow

Follow the relationship between a variable, its address, a pointer, dereferencing, and modifying the original value.

PROGRAM TRACING

๐Ÿ”Ž Program Tracing โ€” Pointers

Trace how a pointer stores an address, modifies the original variable, and reads the updated value through dereferencing.

13.50 Quick MCQs

Select an answer first, then click Check Answer. A correct choice becomes green. If the answer is wrong, your choice becomes red and the correct option becomes green. The explanation appears below.

1. What does a pointer store?
2. Which operator obtains the address of a variable?
3. Which operator dereferences a pointer?
4. What does NULL represent for a pointer?
5. Which function allocates dynamic memory?
6. Which function releases dynamically allocated memory?
PRACTICE

13.51 ๐ŸŽฏ Practice Problems

Pointers become clear through repeated address, dereference, array, string, and dynamic-memory practice. Use ๐Ÿ’ป Solve It Yourself first, open Hint only when needed, and use Show Program after attempting the problem.

๐Ÿ“ˆ Pointers Practice Progress
Solved 0 / 20
Completed with Solution 0
Total Score 0 / 400
Completion 0%
A problem counts as Solved when all test cases pass without opening the full solution. Problems completed after viewing the official solution are tracked separately.
1. Value and Address Relationship

Problem 1: Read an integer, print its value, and verify that a pointer stores the address of that variable.

Input: One integer.

Output: Print the value and "Address Match = Yes".

2. Access a Variable Using a Pointer

Problem 2: Read an integer and print its value by dereferencing a pointer.

Input: One integer.

Output: Print the value obtained through *p.

3. Modify a Variable Using a Pointer

Problem 3: Read an integer and a new value. Modify the original variable through a pointer.

Input: Two integers: original value and new value.

Output: Print the modified variable.

4. Sum of Two Numbers Using Pointers

Problem 4: Read two integers and calculate their sum by dereferencing pointers.

Input: Two integers.

Output: Print the sum.

5. Swap Two Numbers Using Pointers

Problem 5: Swap two integers using a function that receives pointers.

Input: Two integers.

Output: Print the swapped values.

6. Maximum of Two Numbers Using Pointers

Problem 6: Find the larger of two integers using pointers.

Input: Two integers.

Output: Print the maximum value.

7. Print Array Elements Using a Pointer

Problem 7: Read N integers and print every array element using pointer notation.

Input: N followed by N integers.

Output: Print the elements separated by spaces.

8. Sum an Array Using Pointer Arithmetic

Problem 8: Find the sum of an integer array using pointer arithmetic.

Input: N followed by N integers.

Output: Print the sum.

9. Maximum Array Element Using Pointers

Problem 9: Find the maximum element of an integer array using pointer access.

Input: N greater than 0 followed by N integers.

Output: Print the maximum element.

10. Reverse an Array Using Pointers

Problem 10: Reverse an array in place using pointer-based swapping.

Input: N followed by N integers.

Output: Print the reversed array.

11. String Length Using a Pointer

Problem 11: Find the length of a string using pointer traversal.

Input: One line of text.

Output: Print the string length excluding the newline.

12. Reverse a String Using Pointers

Problem 12: Reverse a string in place using pointers.

Input: One line of text.

Output: Print the reversed string.

13. Count Vowels Using a Pointer

Problem 13: Count vowels in a string by traversing it with a pointer.

Input: One line of text.

Output: Print the vowel count.

14. Palindrome String Using Pointers

Problem 14: Check whether a string is a palindrome using left and right pointers.

Input: One line of text.

Output: Print "Palindrome" or "Not Palindrome".

15. Pointer to Pointer

Problem 15: Create a pointer to a pointer and print a variable's value through double dereferencing.

Input: One integer.

Output: Print the value using **pp.

16. Dynamic Integer Array with malloc()

Problem 16: Dynamically allocate an integer array using malloc(), read values, and print their sum.

Input: N followed by N integers.

Output: Print the sum, or Allocation Failed if memory allocation fails.

17. Initial Values with calloc()

Problem 17: Allocate an integer array using calloc() and print its initial values before assigning anything.

Input: One positive integer N.

Output: Print N zero values separated by spaces, or Allocation Failed.

18. Resize an Array with realloc()

Problem 18: Allocate N integers, resize the array to M integers using realloc(), read the new elements, and print the complete resized array.

Input: N, N integers, M where M >= N, followed by M-N new integers.

Output: Print all M elements, or Allocation Failed.

19. Structure Pointer

Problem 19: Create a structure variable and access its members through a structure pointer.

Input: Student roll number and marks.

Output: Print both values using the -> operator.

20. Function Pointer for Addition

Problem 20: Create a function pointer for an addition function and use it to calculate the sum of two integers.

Input: Two integers.

Output: Print their sum.

13.52 Key Takeaway

๐ŸŽฏ Remember this three-part rule:

&x โ†’ Address of x

p โ†’ Address stored in p

*p โ†’ Value at that address

Once this becomes clear, pointers become much easier to understand.
INTERVIEW PREPARATION

๐ŸŽค Pointers โ€” Interview Questions

1. What is the difference between p, &x, and *p?
2. What is a NULL pointer?
3. What is a wild pointer?
4. What is a dangling pointer?
5. How are arrays and pointers related in C?
6. What does pointer arithmetic depend on?
7. Why should realloc() commonly use a temporary pointer?
8. What is a function pointer?
PLACEMENT TIPS

๐Ÿ’ก Pointers โ€” Placement Tips

  • Always separate the three ideas: address, pointer value, and dereferenced object.
  • Initialize pointers before dereferencing them, and check dynamically allocated pointers against NULL.
  • For array-pointer questions, remember arr[i] and *(arr + i) refer to the same element.
  • Pointer arithmetic is scaled by the pointed-to type; p + 1 moves to the next element of that type.
  • After free(p), do not dereference p. Setting it to NULL can help avoid accidental reuse.
  • For realloc(), use a temporary pointer so the original allocation is not lost if resizing fails.
EXTRA PRACTICE

โœ๏ธ Pointers โ€” Extra Practice Questions

  1. Use pointers to find the second largest element of an array.
  2. Use pointer arithmetic to count positive and negative array elements.
  3. Copy one string to another using only pointers.
  4. Concatenate two strings using pointer traversal without strcat().
  5. Dynamically allocate a matrix using pointers and calculate each row sum.
  6. Create an array of function pointers for addition, subtraction, multiplication, and division.
โ† Previous Topic: Functions Next Topic: Structures & Unions โ†’

Worked example: why one swap changes the caller

Question: If C passes arguments by value, how can a function change two variables in its caller?

#include <stdio.h>

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

int swap_at(int *a, int *b) {
    if (a == NULL || b == NULL) return 0;
    int temp = *a;
    *a = *b;
    *b = temp;
    return 1;
}

int main(void) {
    int x = 4, y = 9;
    swap_values(x, y);
    printf("After value call: %d %d\n", x, y);
    swap_at(&x, &y);
    printf("After pointer call: %d %d\n", x, y);
    swap_at(&x, &x);
    printf("Same object: %d\n", x);
    printf("Null rejected: %d\n", swap_at(NULL, &y));
    return 0;
}

Exact output

After value call: 4 9
After pointer call: 9 4
Same object: 9
Null rejected: 0

Follow the values and addresses

  1. swap_values(x, y) copies 4 and 9 into two local parameters. Swapping these copies leaves the callerโ€™s variables unchanged.
  2. swap_at(&x, &y) copies two addresses. The parameters are still passed by value, but *a and *b refer to the callerโ€™s actual integers.
  3. The temporary saves the old value before the first assignment overwrites it. Using only *a = *b; *b = *a; would make both integers equal to 9 for the original inputs.

Boundary cases and limits

Passing the same valid address twice leaves that integer unchanged. A null address is rejected before dereferencing; return value 0 means no swap occurred. A null check cannot detect a dangling, uninitialized or otherwise invalid non-null pointer: both arguments must point to live, writable integers.

Why ฮ˜(1) time and ฮ˜(1) extra space? Every valid call performs a fixed number of checks, reads and assignments, regardless of the integer values. It stores only one temporary integer.