
Chapter 14: Pointers
📚 C Programming – Complete Course Roadmap
⬅ Previous Chapter | Current Chapter: Functions | Next Chapter ➜
Author: Er. Mujtaba Ansari
Pointers allow C programs to work directly with memory for faster and more efficient programming.
Real-Life Uses:
Pointers are widely used in operating systems, embedded systems, dynamic memory management, data structures, arrays, and performance-critical applications.
What is a Pointer in C Programming?

A pointer is a variable that stores the memory address of another variable or object.
A normal variable stores a value, while a pointer stores the address where a value is located in memory.
Example
int x = 10;
int *p;
p = &x;
Here:
xis an integer variable that stores10.&xgives the memory address ofx.pis an integer pointer.pstores the address ofx.
Conceptually:
x = 10
p
|
|-----> x
10
Therefore, a simple definition is:
A pointer is a variable used to store the memory address of another variable or object.
Why are Pointers Used in C?
Pointers are useful in many areas of C Programming.
They are commonly used to:
- Access a variable indirectly
- Modify variables through their addresses
- Pass data efficiently to functions
- Work with arrays and strings
- Access structure members
- Allocate and manage memory dynamically
- Build data structures such as linked lists and trees
- Perform low-level memory operations
Pointer Declaration in C
A pointer is declared using the * symbol.
Syntax
data_type *pointer_name;
Example
int *p;
Here, p is a pointer that can store the address of an int object.
Other examples:
float *fp;
char *cp;
double *dp;
Here:
fpcan store the address of afloatcpcan store the address of achardpcan store the address of adouble
Important Note for YOU
Declaring a pointer does not automatically make it point to a valid variable.
For example:
int *p;
At this point, p should not be dereferenced until it is assigned a valid address.
Address-of Operator (&)
The & operator is called the address-of operator.
It is used to get the memory address of a variable.
Example
int x = 10;
printf("%p", (void *)&x);
Here, &x gives the address of x.
We can store this address in a pointer:
int x = 10;
int *p;
p = &x;
Now, p contains the address of x.
Dereference Operator (*)
The * symbol is also called the dereference operator when it is used with a pointer expression.
Dereferencing a pointer means accessing the value stored in the object to which the pointer points.
Example
#include <stdio.h>
int main(void)
{
int x = 9;
int *p = &x;
printf("Value of x = %d\n", x);
printf("Value using pointer = %d\n", *p);
return 0;
}
Output
Value of x = 9
Value using pointer = 9
Here:
p = &x;
stores the address of x in p.
And:
*p
accesses the value of x.
Understanding & and * Together
Suppose:
int x = 9;
int *p = &x;
Then:
&x
means:
Address of x
And:
*p
means:
Value stored in the object pointed to by p
Therefore:
x → 9
&x → Address of x
p → Address of x
*p → 9
Initializing a Pointer
A pointer should be initialized before it is used.
Example
int x = 25;
int *p = &x;
Now p points to x.
We can access the value using:
printf("%d", *p);
Output:
25
Wild Pointer in C
A pointer that has not been initialized to a valid address is commonly called a wild pointer.
For example:
int *p;
The pointer has been declared, but it does not point to a valid object that we can safely use.
This is dangerous:
*p = 10;
because the program may access an invalid memory location.
A safer approach is:
int x = 10;
int *p = &x;
Or, if the pointer currently has no target:
int *p = NULL;
NULL Pointer
A NULL pointer is a pointer that does not currently point to a valid object.
Example:
int *p = NULL;
Before dereferencing a pointer, we can check whether it is NULL.
if (p != NULL)
{
printf("%d", *p);
}
Never dereference a NULL pointer.
Changing a Variable Using a Pointer
A pointer can be used to change the value of the variable it points to.
Example
#include <stdio.h>
int main(void)
{
int x = 10;
int *p = &x;
printf("Before: %d\n", x);
*p = 25;
printf("After: %d\n", x);
return 0;
}
Output
Before: 10
After: 25
The statement:
*p = 25;
changes the value of x because p points to x.
Pointers and Functions in C
Pointers are very useful when working with functions.
They are commonly used for:
- Passing addresses to functions
- Modifying original variables inside functions
- Returning pointers from functions when the pointed object remains valid
Pointer as a Function Argument
When we pass the address of a variable to a function, the function can modify the original variable through the pointer.
This technique is commonly called call by address.
Important Note for YOU
C does not have true call-by-reference parameters. C always passes arguments by value. When we pass a pointer, the function receives a copy of the address, and that pointer can be used to modify the original object.
Swap Two Numbers Using Pointers
The following program swaps two numbers using pointers.
#include <stdio.h>
void swap(int *p, int *q);
int main(void)
{
int a, b;
printf("Enter two numbers: ");
scanf("%d %d", &a, &b);
printf("Before swap: a = %d, b = %d\n", a, b);
swap(&a, &b);
printf("After swap: a = %d, b = %d\n", a, b);
return 0;
}
void swap(int *p, int *q)
{
int temp;
temp = *p;
*p = *q;
*q = temp;
}
Example Output
Enter two numbers: 5 4
Before swap: a = 5, b = 4
After swap: a = 4, b = 5
Here:
swap(&a, &b);
passes the addresses of a and b.
Inside the function:
*p
and:
*q
are used to access the original variables.
Find the Largest of Two Numbers Using Pointer and Function
We can also use a pointer as the return value of a function.
Program: C Program to Find the Largest of Two Numbers Using Pointers and Functions
#include <stdio.h>
int *largest(int *p, int *q);
int main(void)
{
int a, b;
int *big;
printf("Enter two numbers: ");
scanf("%d %d", &a, &b);
big = largest(&a, &b);
printf("Largest number = %d\n", *big);
return 0;
}
int *largest(int *p, int *q)
{
if (*p > *q)
return p;
else
return q;
}
Example
Input:
5 9
Output:
Largest number = 9
The function returns the pointer to the larger variable.
Important Point for YOU
Do not return the address of a local variable.
Incorrect:
int *getValue(void)
{
int x = 10;
return &x;
}
The local variable x stops existing when the function returns, so returning its address creates an invalid pointer.
Pointer and Structure in C
Pointers can also be used with structures.
Consider the following structure:
struct Complex
{
int real;
int imag;
};
We can create a structure pointer:
struct Complex c;
struct Complex *p = &c;
Now p points to structure c.
Arrow Operator (->)
The -> operator is used to access structure members through a structure pointer.
For example:
p->real
is equivalent to:
(*p).real
Similarly:
p->imag
is equivalent to:
(*p).imag
Add Two Complex Numbers Using Structure Pointers
#include <stdio.h>
struct Complex
{
int real;
int imag;
};
int main(void)
{
struct Complex a, b, c;
struct Complex *p = &a;
struct Complex *q = &b;
struct Complex *r = &c;
printf("Enter real and imaginary parts of first number: ");
scanf("%d %d", &p->real, &p->imag);
printf("Enter real and imaginary parts of second number: ");
scanf("%d %d", &q->real, &q->imag);
r->real = p->real + q->real;
r->imag = p->imag + q->imag;
printf("Result = %d + %di\n", r->real, r->imag);
return 0;
}
Here, the structure members are accessed using the arrow operator.
Pointer Inside a Structure
A structure can also contain a pointer as one of its members.
Example
struct Student
{
int roll;
char name[20];
int *marks;
};
Now:
struct Student student;
int marks = 95;
student.marks = &marks;
The structure member marks is a pointer that stores the address of the variable marks.
We can access the value using:
*student.marks
Example: C Program to Use a Pointer as a Structure Member
#include <stdio.h>
struct Student
{
int roll;
char name[20];
int *marks;
};
int main(void)
{
struct Student student;
int marks = 95;
student.roll = 7;
student.marks = &marks;
printf("Roll = %d\n", student.roll);
printf("Marks = %d\n", *student.marks);
return 0;
}
Pointer and Array in C
Pointers and arrays are closely related in C.
Consider:
int a[5] = {20, 8, 91, 12, 9};
The first element is:
a[0]
and its address is:
&a[0]
In most expressions, the array name a is converted to a pointer to its first element.
Therefore:
a
corresponds to:
&a[0]
We can write:
int *p = a;
or:
int *p = &a[0];
Both initialize p to point to the first element.
Important Correction
It is common to hear:
“An array name is a constant pointer.”
This is a useful beginner shortcut, but it is not technically accurate.
An array is not a pointer. In most expressions, the array name decays to a pointer to its first element.
For example:
a = a + 1;
is invalid.
But:
p = p + 1;
is valid when p is a pointer variable.
Accessing Array Elements Using a Pointer
Suppose:
int a[5] = {20, 8, 91, 12, 9};
int *p = a;
The following expressions can access array elements:
a[0]
*(a + 0)
p[0]
*(p + 0)
All of them access the first element.
Similarly:
a[2]
p[2]
*(a + 2)
*(p + 2)
access the third element.
Pointer Arithmetic
Pointer arithmetic is commonly used with arrays.
Suppose:
int *p = a;
Then:
p + 1
points to the next int element.
Conceptually:
p → a[0]
p + 1 → a[1]
p + 2 → a[2]
p + 3 → a[3]
p + 4 → a[4]
Pointer arithmetic is scaled according to the size of the pointed-to type. It does not simply mean adding one byte.
*(p + i) vs *p + i
This is an important concept for beginners.
Suppose:
int a[5] = {20, 8, 91, 12, 9};
int *p = a;
Then:
*(p + 4)
accesses the fifth element:
9
But:
*p + 4
means:
20 + 4
which gives:
24
Therefore:
*(p + 4) // 9
*p + 4 // 24
The parentheses make a major difference.
Find the Largest Element in an Array Using Pointer
#include <stdio.h>
int main(void)
{
int a[100];
int n;
int i;
int largest;
int *p;
printf("Enter array size: ");
scanf("%d", &n);
if (n <= 0 || n > 100)
{
printf("Invalid array size.\n");
return 1;
}
printf("Enter array elements: ");
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
p = a;
largest = *p;
for (i = 1; i < n; i++)
{
if (*(p + i) > largest)
{
largest = *(p + i);
}
}
printf("Largest element = %d\n", largest);
return 0;
}
Find the Largest and Second Largest Elements Using Pointer
The following program finds the largest and second-largest distinct elements.
#include <stdio.h>
#include <limits.h>
int main(void)
{
int a[100];
int n, i;
int largest = INT_MIN;
int secondLargest = INT_MIN;
int *p = a;
printf("Enter array size: ");
scanf("%d", &n);
if (n < 2 || n > 100)
{
printf("Array must contain at least two elements.\n");
return 1;
}
printf("Enter array elements: ");
for (i = 0; i < n; i++)
{
scanf("%d", &a[i]);
}
for (i = 0; i < n; i++)
{
if (*p > largest)
{
secondLargest = largest;
largest = *p;
}
else if (*p > secondLargest && *p < largest)
{
secondLargest = *p;
}
p++;
}
if (secondLargest == INT_MIN)
{
printf("No distinct second largest element exists.\n");
}
else
{
printf("Largest element = %d\n", largest);
printf("Second largest element = %d\n", secondLargest);
}
return 0;
}
Pointer and String in C
In C, a string is a sequence of characters terminated by the null character '\0'.
Example:
char city[10] = "Pune";
It is stored conceptually as:
P u n e \0
We can create a pointer to the first character:
char *p = city;
Now:
printf("%s", p);
prints:
Pune
And:
printf("%c", p[2]);
prints:
n
Character Array vs Pointer to String Literal
These two declarations are different:
Character Array
char city[] = "Pune";
This creates a character array that can be modified.
For example:
city[0] = 'D';
is valid.
Pointer to String Literal
const char *city = "Pune";
Here, city points to a string literal. The string should not be modified through this pointer.
Using const clearly indicates that the pointed characters are not intended to be changed.
Array of Pointers to Strings
An array can contain pointers to different strings.
Example:
const char *city[] =
{
"Gaya",
"Delhi",
"Ranchi",
"Bangalore"
};
Here:
city[0]
points to "Gaya".
city[1]
points to "Delhi".
Program: C Program to Store and Display Strings Using an Array of Pointers
#include <stdio.h>
int main(void)
{
const char *city[] =
{
"Gaya",
"Delhi",
"Ranchi",
"Bangalore"
};
int i;
for (i = 0; i < 4; i++)
{
printf("%s\n", city[i]);
}
return 0;
}
Output
Gaya
Delhi
Ranchi
Bangalore
Pointer to Pointer in C
A pointer can also store the address of another pointer.
This is called a pointer to pointer.
Example:
int x = 10;
int *p = &x;
int **q = &p;
The relationship is:
q → p → x
Here:
*p
gives the value of x.
And:
**q
also gives the value of x.
Example: C Program to Demonstrate Pointer to Pointer (Double Pointer)
#include <stdio.h>
int main(void)
{
int x = 10;
int *p = &x;
int **q = &p;
printf("x = %d\n", x);
printf("*p = %d\n", *p);
printf("**q = %d\n", **q);
return 0;
}
Output
x = 10
*p = 10
**q = 10
Pointers and Dynamic Memory Allocation
Pointers are essential for dynamic memory allocation in C.
Dynamic memory can be allocated during program execution using functions such as:
malloc()calloc()realloc()free()
These functions are declared in:
#include <stdlib.h>
Example Using malloc()
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int n;
int *p;
printf("Enter number of elements: ");
scanf("%d", &n);
if (n <= 0)
{
printf("Invalid number of elements.\n");
return 1;
}
p = malloc((size_t)n * sizeof *p);
if (p == NULL)
{
printf("Memory allocation failed.\n");
return 1;
}
for (int i = 0; i < n; i++)
{
p[i] = (i + 1) * 10;
}
for (int i = 0; i < n; i++)
{
printf("%d ", p[i]);
}
free(p);
return 0;
}
Here:
malloc()
allocates memory dynamically.
After using the allocated memory:
free(p);
releases it.
Common Pointer Mistakes in C
Pointers are powerful, but incorrect use can lead to undefined behavior, crashes, or memory-related bugs.
1. Using an Uninitialized Pointer
Incorrect:
int *p;
*p = 10;
The pointer does not point to a valid object.
Correct:
int x = 10;
int *p = &x;
2. Dereferencing a NULL Pointer
Incorrect:
int *p = NULL;
printf("%d", *p);
A NULL pointer must not be dereferenced.
3. Returning the Address of a Local Variable
Incorrect:
int *getValue(void)
{
int x = 10;
return &x;
}
The local variable no longer exists after the function returns.
4. Accessing Memory After free()
Incorrect:
free(p);
printf("%d", *p);
After free(p), the allocated object must no longer be accessed through p.
A common practice is:
free(p);
p = NULL;
when the pointer remains in scope and will not immediately be reused.
5. Going Outside an Array
If:
int a[5];
valid element indexes are:
0 to 4
Accessing:
a[5]
is outside the array and causes undefined behavior.
The same rule applies to pointer arithmetic.
Pointer and Normal Variable: Difference

| Feature | Normal Variable | Pointer |
|---|---|---|
| Stores | A value | An address |
| Example | int x = 10; | int *p = &x; |
| Access | Direct | Indirect |
| Address | &x | p |
| Access pointed value | Not applicable | *p |
| Common use | Store data | Work with addresses and indirect access |
Important Pointer Operators
| Operator | Name | Purpose |
|---|---|---|
& | Address-of operator | Gets the address of an object |
* | Dereference operator | Accesses the object pointed to |
-> | Arrow operator | Accesses a structure member through a pointer |
Important Pointer and Array Expressions
Suppose:
int a[5] = {10, 20, 30, 40, 50};
int *p = a;
Then:
a[0] → 10
*p → 10
p[0] → 10
*(p + 0) → 10
For the third element:
a[2] → 30
p[2] → 30
*(a + 2) → 30
*(p + 2) → 30
Some Key Points to Remember About Pointers
Before moving to advanced C Programming, remember these important points:
- A pointer stores an address.
&is used to obtain an object’s address.*is used to dereference a pointer.- A pointer should be initialized before it is dereferenced.
NULLrepresents a pointer that does not point to a valid object.- Pointer arithmetic is commonly used with arrays.
p[i]is equivalent to*(p + i)for a pointerp.- Structure pointers commonly use the
->operator. - Pointers allow functions to modify caller-owned objects.
- Pointers are essential for dynamic memory allocation.
- Invalid pointer operations can cause undefined behavior.
- Memory allocated with
malloc(),calloc(), orrealloc()should eventually be released withfree()when it is no longer needed.
Frequently Asked Questions (FAQs)
What is a pointer in C?
A pointer is a variable that stores the memory address of another variable or object.
What is the use of & in C?
The & operator returns the address of an object.
Example:
int x = 10;
int *p = &x;
What is dereferencing?
Dereferencing means accessing the object stored at the address held by a pointer.
Example:
*p
accesses the value of the object pointed to by p.
What is a wild pointer?
A wild pointer is an uninitialized pointer that has not been assigned a valid address before being used.
What is a NULL pointer?
A NULL pointer is a pointer that does not currently point to a valid object.
Example:
int *p = NULL;
Does C support call by reference?
C uses pass-by-value. However, pointers can be passed to functions so that the function can modify the original object. This technique is commonly called call by address.
What is pointer arithmetic?
Pointer arithmetic allows operations such as incrementing or decrementing a pointer, particularly when working with arrays.
What is a structure pointer?
A structure pointer is a pointer that stores the address of a structure object.
Example:
struct Student s;
struct Student *p = &s;
What is the -> operator?
The -> operator is used to access a structure member through a structure pointer.
Example:
p->roll
Why are pointers important in C?
Pointers are important because they provide direct and indirect access to memory and are widely used with functions, arrays, strings, structures, dynamic memory, and data structures.
Conclusion
Pointers are one of the most powerful and important features of C Programming. A pointer stores the memory address of an object and allows the program to access that object indirectly.
The basic pointer concept can be remembered with this simple example:
int x = 10;
int *p = &x;
printf("%d", *p);
Here:
x → stores 10
&x → gives the address of x
p → stores the address of x
*p → accesses the value of x
Once you understand this relationship, concepts such as pointer arithmetic, functions, arrays, strings, structures, pointer to pointer, and dynamic memory allocation become much easier to understand.
Pointers are not just an advanced topic in C. They are a fundamental part of the language and form the foundation for many important programming concepts and data structures.

Mujtaba Ansari is a Software Engineer, Founder & CEO of The Tech Earth. He writes about technology, AI, software, cybersecurity, blogging, Health tech, Agri Tech and digital trends to help readers stay updated with the latest innovations.
