Chapter 12: Pointers
- LO 12.1: Understand the concept of pointers and memory addressing
- LO 12.2: Declare and initialize pointer variables
- LO 12.3: Perform pointer arithmetic and understand scale factor
- LO 12.4: Use pointers with arrays and strings
- LO 12.5: Work with pointers to functions and structures
- LO 12.6: Understand pointer compatibility and common pointer errors
12.1 Introduction to Pointers
A pointer is a derived data type in C that stores memory addresses as their values. Pointers contain the addresses of other variables, allowing indirect access to data stored in memory.
Memory organization:
Address Value
+------+------+
| 1000 | 179 | ← variable quantity
+------+------+
| 1002 | 200 |
+------+------+
| 1004 | 150 |
+------+------+
| 5000 | 1000 | ← pointer p pointing to quantity
+------+------+
If int quantity = 179 at address 1000,
and int *p = &quantity at address 5000,
then:
p = 1000 (address of quantity)
*p = 179 (value of quantity)
Benefits of pointers:
- Pointers can be used to return multiple values from a function via function arguments
- Pointers permit references to functions, facilitating passing functions as arguments
- The use of pointer arrays to character strings saves data storage space
- Pointers allow C to support dynamic memory management
- Pointers provide an efficient tool for manipulating dynamic data structures
12.2 Understanding Pointers
Every variable in memory has an address. The address operator & gives the address of a variable.
📝 Worked-Out Problem 12.1
Accessing the address of a variable:
#include <stdio.h>
int main() {
int a = 10;
float b = 20.5;
char c = 'X';
printf("Value of a = %d, Address of a = %u\n", a, &a);
printf("Value of b = %.2f, Address of b = %u\n", b, &b);
printf("Value of c = %c, Address of c = %u\n", c, &c);
return 0;
}
Value of a = 10, Address of a = 3221224900
Value of b = 20.50, Address of b = 3221224896
Value of c = X, Address of c = 3221224895
Note: The actual addresses may vary each time the program runs.
12.3 Declaring Pointer Variables
Pointer variables are declared using the asterisk (*) operator:
data_type *pointer_name;
Examples:
int *p; // pointer to integer float *x; // pointer to float char *ch; // pointer to character
12.4 Initialization of Pointer Variables
Pointers must be initialized before use. They can be initialized with the address of a variable or NULL.
int quantity = 179; int *p = &quantity; // Initialize at declaration // Or separately int *p; p = &quantity; // Assign address after declaration // NULL pointer int *ptr = NULL; // Points to nothing
12.5 Accessing a Variable Through its Pointer
The indirection operator (*) gives the value at the address stored in a pointer.
📝 Worked-Out Problem 12.2
Accessing variables through pointers:
#include <stdio.h>
int main() {
int x = 10;
int *ptr;
ptr = &x; // ptr stores address of x
printf("Value of x = %d\n", x);
printf("Address of x = %u\n", &x);
printf("Value of ptr = %u\n", ptr);
printf("Value pointed by ptr = %d\n", *ptr);
*ptr = 25; // Change x through pointer
printf("New value of x = %d\n", x);
return 0;
}
Value of x = 10
Address of x = 3221224900
Value of ptr = 3221224900
Value pointed by ptr = 10
New value of x = 25
12.6 Chain of Pointers
Pointers can point to other pointers, creating a chain of indirection.
int x = 10;
int *p = &x; // pointer to int
int **q = &p; // pointer to pointer to int
int ***r = &q; // pointer to pointer to pointer to int
printf("x = %d\n", x);
printf("*p = %d\n", *p);
printf("**q = %d\n", **q);
printf("***r = %d\n", ***r);
Chain of pointers:
r (address 3000) ──→ q (address 2000) ──→ p (address 1000) ──→ x (value 10)
| | |
↓ ↓ ↓
value 2000 value 1000 value 10
12.7 Pointer Expressions and Arithmetic
Pointers can be used in expressions with certain arithmetic operations:
- Adding an integer to a pointer:
ptr + n - Subtracting an integer from a pointer:
ptr - n - Subtracting one pointer from another:
ptr1 - ptr2 - Comparing pointers:
ptr1 > ptr2,ptr1 == ptr2, etc.
Invalid pointer operations:
- Multiplying or dividing pointers
- Adding two pointers
- Assigning an absolute address (except NULL)
12.8 Pointer Increments and Scale Factor
When a pointer is incremented, it points to the next element of its type. The increment is multiplied by the size of the data type (scale factor).
int *p = (int *)1000; // Assuming int is 4 bytes p++; // p now points to address 1004 (1000 + 4)
| Data Type | Size (bytes) | Scale Factor |
|---|---|---|
| char | 1 | 1 |
| int | 4 (typical) | 4 |
| float | 4 | 4 |
| double | 8 | 8 |
📝 Worked-Out Problem 12.3
Pointer increments and scale factor:
#include <stdio.h>
int main() {
int i = 100;
int *int_ptr = &i;
float f = 3.14;
float *float_ptr = &f;
char c = 'A';
char *char_ptr = &c;
printf("int_ptr = %u\n", int_ptr);
int_ptr++;
printf("int_ptr after increment = %u\n", int_ptr);
printf("Difference = %u\n\n", int_ptr - &i);
printf("float_ptr = %u\n", float_ptr);
float_ptr++;
printf("float_ptr after increment = %u\n", float_ptr);
printf("Difference = %u\n\n", float_ptr - &f);
printf("char_ptr = %u\n", char_ptr);
char_ptr++;
printf("char_ptr after increment = %u\n", char_ptr);
printf("Difference = %u\n", char_ptr - &c);
return 0;
}
int_ptr = 3221224900
int_ptr after increment = 3221224904
Difference = 4
float_ptr = 3221224896
float_ptr after increment = 3221224900
Difference = 4
char_ptr = 3221224895
char_ptr after increment = 3221224896
Difference = 1
12.9 Pointers and Arrays
The name of an array is a constant pointer to the first element of the array.
int x[5] = {10, 20, 30, 40, 50};
int *p;
p = x; // p points to x[0] (same as p = &x[0])
printf("%d", *p); // prints 10
p++; // now p points to x[1]
printf("%d", *p); // prints 20
Relationship between pointers and arrays:
p = &x[0]; // p points to first element x[i] ≡ *(x + i) // array indexing using pointer arithmetic &x[i] ≡ (x + i) // address of element i
📝 Worked-Out Problem 12.4
Accessing array elements using pointers:
#include <stdio.h>
int main() {
int x[5] = {10, 20, 30, 40, 50};
int *p, i;
p = x; // p points to x[0]
printf("Using array indexing:\n");
for (i = 0; i < 5; i++)
printf("x[%d] = %d\t Address = %u\n", i, x[i], &x[i]);
printf("\nUsing pointer arithmetic:\n");
for (i = 0; i < 5; i++)
printf("*(p+%d) = %d\t Address = %u\n", i, *(p+i), p+i);
printf("\nUsing pointer increment:\n");
p = x;
for (i = 0; i < 5; i++) {
printf("*p = %d\t Address = %u\n", *p, p);
p++;
}
return 0;
}
12.10 Pointers and Two-Dimensional Arrays
For a two-dimensional array, we need to understand how elements are stored in row-major order.
int a[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
The element a[i][j] can be accessed using pointer notation as:
*(*(a + i) + j) // Equivalent to a[i][j]
📝 Worked-Out Problem 12.5
Accessing 2D array elements using pointers:
#include <stdio.h>
int main() {
int a[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
int i, j;
int *p;
printf("Using array indexing:\n");
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++)
printf("%4d", a[i][j]);
printf("\n");
}
printf("\nUsing pointer arithmetic:\n");
for (i = 0; i < 3; i++) {
for (j = 0; j < 4; j++)
printf("%4d", *(*(a + i) + j));
printf("\n");
}
printf("\nTreating 2D as 1D:\n");
p = &a[0][0]; // pointer to first element
for (i = 0; i < 12; i++)
printf("%d ", *(p + i));
printf("\n");
return 0;
}
12.11 Pointers and Character Strings
Strings can be accessed using character pointers.
char *str = "Hello World";
📝 Worked-Out Problem 12.6
String handling using pointers:
#include <stdio.h>
int string_length(char *str) {
int len = 0;
while (*str != '\0') {
len++;
str++;
}
return len;
}
void string_copy(char *dest, char *src) {
while (*src != '\0') {
*dest = *src;
dest++;
src++;
}
*dest = '\0';
}
int main() {
char *str1 = "Hello World";
char str2[50];
printf("String: %s\n", str1);
printf("Length: %d\n", string_length(str1));
string_copy(str2, str1);
printf("Copied string: %s\n", str2);
// Printing characters using pointer
char *p = str1;
printf("Characters: ");
while (*p != '\0')
printf("%c ", *p++);
printf("\n");
return 0;
}
String: Hello World
Length: 11
Copied string: Hello World
Characters: H e l l o W o r l d
12.12 Array of Pointers
We can create arrays that store pointers. This is particularly useful for handling multiple strings.
char *names[5] = {
"John",
"Alice",
"Bob",
"David",
"Charlie"
};
This creates a "ragged array" where each string occupies only the space it needs, unlike a 2D character array which wastes space.
📝 Worked-Out Problem 12.7
Array of pointers to strings:
#include <stdio.h>
int main() {
char *cities[5] = {
"Mumbai",
"Delhi",
"Chennai",
"Kolkata",
"Bangalore"
};
int i;
printf("List of cities:\n");
for (i = 0; i < 5; i++)
printf("%d. %s (address: %u)\n", i+1, cities[i], cities[i]);
printf("\nAccessing characters in the first city:\n");
char *p = cities[0];
while (*p != '\0')
printf("%c ", *p++);
printf("\n");
return 0;
}
12.13 Pointers as Function Arguments (Call by Reference)
Passing pointers to functions allows the function to modify the original variables in the calling function.
📝 Worked-Out Problem 12.8
Swapping values using pointers:
#include <stdio.h>
void swap(int *a, int *b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 10, y = 20;
printf("Before swap: x = %d, y = %d\n", x, y);
swap(&x, &y); // Pass addresses
printf("After swap: x = %d, y = %d\n", x, y);
return 0;
}
Before swap: x = 10, y = 20
After swap: x = 20, y = 10
📝 Worked-Out Problem 12.9
Function returning multiple values using pointers:
#include <stdio.h>
void math_ops(int a, int b, int *sum, int *diff, int *prod, float *quot) {
*sum = a + b;
*diff = a - b;
*prod = a * b;
if (b != 0)
*quot = (float)a / b;
else
*quot = 0;
}
int main() {
int x = 15, y = 4;
int s, d, p;
float q;
math_ops(x, y, &s, &d, &p, &q);
printf("x = %d, y = %d\n", x, y);
printf("Sum = %d\n", s);
printf("Difference = %d\n", d);
printf("Product = %d\n", p);
printf("Quotient = %.2f\n", q);
return 0;
}
x = 15, y = 4
Sum = 19
Difference = 11
Product = 60
Quotient = 3.75
12.14 Functions Returning Pointers
A function can return a pointer, provided the memory it points to remains valid after the function returns.
int *larger(int *x, int *y) {
if (*x > *y)
return x;
else
return y;
}
int main() {
int a = 10, b = 20;
int *p = larger(&a, &b);
printf("Larger value: %d\n", *p);
return 0;
}
12.15 Pointers to Functions
Like variables, functions also have addresses. We can create pointers to functions and use them to call functions indirectly.
return_type (*pointer_name)(parameter_list);
📝 Worked-Out Problem 12.10
Using pointers to functions:
#include <stdio.h>
#include <math.h>
double square(double x) {
return x * x;
}
double cube(double x) {
return x * x * x;
}
void table(double (*f)(double), double start, double end, double step) {
double x;
printf("x\tf(x)\n");
for (x = start; x <= end; x += step) {
printf("%.2f\t%.4f\n", x, (*f)(x));
}
printf("\n");
}
int main() {
printf("Square function:\n");
table(square, 1.0, 5.0, 1.0);
printf("Cube function:\n");
table(cube, 1.0, 5.0, 1.0);
printf("Sine function:\n");
table(sin, 0.0, 3.14, 1.0);
return 0;
}
Square function:
x f(x)
1.00 1.0000
2.00 4.0000
3.00 9.0000
4.00 16.0000
5.00 25.0000
12.16 Pointers and Structures
Pointers to structures are commonly used, especially when passing structures to functions.
struct student {
int roll_no;
char name[30];
float marks;
};
struct student s1 = {101, "John", 85.5};
struct student *ptr = &s1;
// Access members using pointer
printf("Roll: %d\n", ptr->roll_no); // using arrow operator
printf("Name: %s\n", ptr->name); // ptr->member is equivalent to (*ptr).member
📝 Worked-Out Problem 12.11
Array of structures using pointers:
#include <stdio.h>
struct student {
int roll_no;
char name[30];
float marks;
};
int main() {
struct student s[3] = {
{101, "John", 85.5},
{102, "Alice", 92.0},
{103, "Bob", 78.5}
};
struct student *ptr;
int i;
ptr = s; // ptr points to first structure
printf("Using array indexing:\n");
for (i = 0; i < 3; i++)
printf("%d\t%s\t%.2f\n", s[i].roll_no, s[i].name, s[i].marks);
printf("\nUsing pointer:\n");
for (i = 0; i < 3; i++) {
printf("%d\t%s\t%.2f\n", (ptr+i)->roll_no, (ptr+i)->name, (ptr+i)->marks);
}
printf("\nUsing pointer increment:\n");
ptr = s;
for (i = 0; i < 3; i++) {
printf("%d\t%s\t%.2f\n", ptr->roll_no, ptr->name, ptr->marks);
ptr++;
}
return 0;
}
12.17 Pointer Compatibility and Casting
Pointers to different types are generally incompatible and cannot be assigned directly without casting.
int x = 10; float *fp; fp = &x; // Error: incompatible types fp = (float *)&x; // Allowed with cast, but dangerous
void pointer: A generic pointer that can point to any data type.
void *ptr;
int x = 10;
float f = 3.14;
ptr = &x; // void pointer can point to int
ptr = &f; // and also to float
// Must cast before dereferencing
printf("%d", *(int *)ptr); // cast to appropriate type
12.18 Common Pointer Errors
- Uninitialized pointers: Using a pointer before assigning a valid address
- Forgetting & in scanf:
scanf("%d", ptr);when ptr is uninitialized - Dangling pointers: Using a pointer after the memory it points to is freed
- Memory leaks: Losing the address of dynamically allocated memory
- Comparing incompatible pointers: Comparing pointers to different types
- Incorrect pointer arithmetic: Not accounting for scale factor
- Missing * in pointer declaration vs dereferencing confusion
Important Points to Remember
- Only addresses of variables can be stored in pointer variables, not arbitrary values.
- Do not store the address of a variable of one type into a pointer variable of another type without proper casting.
- Pointer variables contain garbage until initialized; always initialize before use.
- NULL (0) can be assigned to a pointer to indicate it points to nothing.
- When an array is passed to a function, a pointer is actually passed (call by reference).
- If a called function needs to modify a variable in the calling function, pass its address.
- Be careful with operator precedence:
*p++increments the pointer, not the value pointed to.
Chapter Exercises
Review Questions
- State true or false:
a) Pointer constants are the addresses of memory locations.
b) The underlying type of a pointer variable is void.
c) Pointer variables are declared using the address operator.
d) It is possible to cast a pointer to float as a pointer to integer.
e) Pointers to pointers can be used to describe pointers whose contents are the address of another pointer.
f) A pointer can never be subtracted from another pointer.
g) An integer can be added to a pointer.
h) Pointers can be used as formal parameters in function headers.
i) When an array is passed to a function, a pointer is passed. - What is a pointer? How can it be initialized?
- Explain the effects of:
int a, *b = &a; - Distinguish between
(*m)[5]and*m[5]. - What is printed by:
printf("%u %u", &a, &a+1);if a is an integer array?
Multiple Choice Questions
- A pointer in C language is:
a) address of some location
b) useful to describe linked list
c) can be used to access elements of an array
d) All of the above - Which constant values can be assigned to a pointer variable?
a) 0
b) NULL
c) Neither
d) Both 1 and 2 - Which of the following operations is allowed on a pointer variable?
a) ptr+1
b) ptr-1
c) ptr++ and ptr--
d) All of these - Which of the following is incorrect about pointers?
a) A pointer variable stores NULL until initialized.
b) A pointer cannot be assigned any numeric constant except 0.
c) Except for void pointer, assigning one pointer type to another without cast is error.
d) The address operator (&) is not required when assigning array address to pointer. - Given
int x = 10, y = 10; int *p1 = &x, *p2 = &y;, what is(*p1)++?
a) 10
b) 11
c) address of x
d) None
Debugging Exercises
Find errors in the following code segments:
int *p;
*p = 25; // Error?
int x = 10;
float *fp = &x; // Error?
char *str = "Hello";
str[0] = 'h'; // Error?
int a[5] = {1,2,3,4,5};
int *p = a;
p = p + 1.5; // Error?
int x = 10;
int *p = &x;
int **q = p; // Error?
Programming Exercises
- Write a program using pointers to read an array of integers and print its elements in reverse order.
- Write a function to calculate the roots of a quadratic equation using pointer parameters to return the roots.
- Write a function that receives a sorted array and an integer, and inserts the value in its correct place using pointers.
- Write a function using pointers to add two matrices and return the result to the calling function.
- Write a function that receives a string and a character, and deletes all occurrences of that character using pointers.
- Write a function
day_namethat receives a number n and returns a pointer to the name of the corresponding day. - Write a program to sort an array of names using pointers and function pointers for comparison.
- Write a function to search for a particular item using binary search, using pointers and pointer arithmetic.
- Write a function that reverses the elements of a given array using pointer parameters.
- Write a C program to demonstrate the scale factor by incrementing pointers of different types.
Interview Questions
- Which format specifiers are used to print the address of a pointer?
- What is a pointer to a pointer? Give an example.
- What will be the output of:
char *ptr = "Hello"; printf("%d %d", sizeof(*ptr), sizeof(ptr)); - What is a null pointer?
- What is a function pointer?
- What is a void pointer?
- What is the difference between an uninitialized pointer and a NULL pointer?
- What will be the output of:
int arr[] = {10, 20, 30, 40, 50}; int *p = arr; printf("%d %d", *p++, *p++);
Case Study: Processing Examination Marks
📝 Case Study: Rank list preparation using pointers
#include <stdio.h>
#include <string.h>
#define STUDENTS 5
#define SUBJECTS 3
struct student {
char name[30];
int marks[SUBJECTS];
int total;
};
void calculate_totals(struct student *s, int n) {
int i, j;
for (i = 0; i < n; i++) {
s[i].total = 0;
for (j = 0; j < SUBJECTS; j++)
s[i].total += s[i].marks[j];
}
}
void sort_by_total(struct student *s, int n) {
int i, j;
struct student temp;
for (i = 0; i < n-1; i++) {
for (j = 0; j < n-i-1; j++) {
if (s[j].total < s[j+1].total) {
temp = s[j];
s[j] = s[j+1];
s[j+1] = temp;
}
}
}
}
void print_rank_list(struct student *s, int n) {
int i;
printf("\nRank List:\n");
printf("Rank\tName\t\tTotal\n");
for (i = 0; i < n; i++)
printf("%d\t%s\t\t%d\n", i+1, s[i].name, s[i].total);
}
int main() {
struct student s[STUDENTS] = {
{"John", {85, 90, 88}, 0},
{"Alice", {92, 88, 95}, 0},
{"Bob", {78, 82, 80}, 0},
{"David", {88, 85, 90}, 0},
{"Emma", {95, 92, 98}, 0}
};
calculate_totals(s, STUDENTS);
sort_by_total(s, STUDENTS);
print_rank_list(s, STUDENTS);
return 0;
}
Rank List:
Rank Name Total
1 Emma 285
2 Alice 275
3 John 263
4 David 263
5 Bob 240
Case Study 2: Inventory Management
📝 Case Study: Inventory updating with structure pointers
#include <stdio.h>
struct stores {
char name[30];
float price;
int quantity;
};
void update(struct stores *product, float p_inc, int q_inc) {
product->price += p_inc;
product->quantity += q_inc;
}
float total_value(struct stores *product) {
return product->price * product->quantity;
}
int main() {
struct stores item = {"Laptop", 45000.00, 10};
printf("Original: %s, Price: %.2f, Quantity: %d\n",
item.name, item.price, item.quantity);
printf("Total value: Rs. %.2f\n\n", total_value(&item));
update(&item, 2000.00, 5);
printf("After update: %s, Price: %.2f, Quantity: %d\n",
item.name, item.price, item.quantity);
printf("Total value: Rs. %.2f\n", total_value(&item));
return 0;
}
Original: Laptop, Price: 45000.00, Quantity: 10
Total value: Rs. 450000.00
After update: Laptop, Price: 47000.00, Quantity: 15
Total value: Rs. 705000.00