Pointers in C
A Comprehensive Guide
What Are Pointers?
In C programming, pointers are variables that store the memory address of another variable. They are one of the most powerful features of C because they allow you to work directly with memory, offering flexibility and efficiency in memory manipulation.
Why Use Pointers?
- Efficiency: Pointers allow you to directly access and manipulate memory, which can lead to faster and more efficient programs.
- Dynamic Memory Allocation: Pointers are essential when dealing with functions like
malloc()andcalloc(), which allocate memory at runtime. - Function Arguments: Pointers allow passing references to variables, enabling call by reference and modifying variables within functions.
- Data Structures: Pointers are crucial in implementing complex data structures like linked lists, trees, and graphs.
Basics of Pointers
Declaring a Pointer:
int *ptr; // Declares a pointer to an integerPointer Initialization: You can initialize a pointer by storing the address of a variable using the address-of operator (&).
int x = 10; int *ptr = &x; // ptr stores the address of xDereferencing a Pointer: The dereference operator (*) accesses the value at the memory address stored by the pointer.
printf("%d", *ptr); // Outputs 10 (value of x)Types of Pointers in C
In C, there are several types of pointers, each serving a specific purpose. Here’s a breakdown of the most important ones:
1. Null Pointer
- A null pointer is a pointer that doesn’t point to any valid memory location. It is often used to signify that a pointer is not yet assigned.
int *p = NULL;
if (p == NULL) {
printf("Pointer is null.\n");
}2. Void Pointer (Generic Pointer)
- A
voidpointer can point to any data type, but it must be typecasted to a specific type before dereferencing.
void *ptr;
int a = 5;
ptr = &a; // Can point to any type of data
printf("%d\n", *(int*)ptr); // Typecast to int* before dereferencing3. Dangling Pointer
- A dangling pointer is a pointer that points to memory that has been freed or deallocated. It can cause undefined behavior if dereferenced.
int *p = (int*) malloc(sizeof(int));
*p = 10;
free(p); // Memory is deallocated
// Now p is a dangling pointer4. Wild Pointer
- A wild pointer is an uninitialized pointer, which means it points to a random memory location. Using a wild pointer can lead to unpredictable behavior.
int *p; // Uninitialized pointer
*p = 10; // This can cause a crash or unexpected behavior5. Constant Pointer
- A constant pointer is a pointer that cannot change the address it’s pointing to, though the value at that address may change.
int x = 10;
int *const p = &x; // Constant pointer
*p = 20; // Allowed, value at p can change
// p = &y; // Not allowed, p can't change the address it holds6. Pointer to Constant
- A pointer to constant means that the value being pointed to cannot be modified, though the pointer itself can point to another address.
const int x = 10;
const int *p = &x; // Pointer to constant
// *p = 20; // Not allowed, value can't be modified
p = &y; // Allowed, pointer can change the address7. Function Pointer
- Function pointers can be used to implement the strategy pattern, where the behavior of a program changes at runtime based on a specific strategy (or function) selected.
#include <stdio.h>
// Different strategies
void addition(int a, int b) {
printf("Sum: %d\n", a + b);
}
void subtraction(int a, int b) {
printf("Difference: %d\n", a - b);
}
// Function that accepts different strategies via function pointer
void executeOperation(void (*operation)(int, int), int a, int b) {
operation(a, b); // Call the chosen operation (addition or subtraction)
}
int main() {
void (*op)(int, int);
// Choose addition strategy
op = addition;
executeOperation(op, 10, 5); // Outputs: Sum: 15
// Choose subtraction strategy
op = subtraction;
executeOperation(op, 10, 5); // Outputs: Difference: 5
return 0;
}8. Pointer to Pointer (Double Pointer)
- A pointer to pointer is a pointer that holds the address of another pointer. It’s often used in multi-dimensional arrays or when manipulating dynamically allocated memory.
int x = 10;
int *p = &x; // Pointer to int
int **pp = &p; // Pointer to pointer to int
printf("%d", **pp); // Outputs 10Working with Pointers Examples(call by refrence)
Here’s a simple example showing how pointers can be used to modify the value of a variable inside a function:
#include <stdio.h>
void modify(int *p) {
*p = 20; // Modify the value of the variable at the address stored in p
}
int main() {
int x = 10;
printf("Before: %d\n", x); // Outputs 10
modify(&x); // Pass the address of x to the function
printf("After: %d\n", x); // Outputs 20
return 0;
}The modify() function takes a pointer to an integer and modifies the value stored at that address.
Advanced Pointer Concepts
1. Pointer Arithmetic
Pointers support arithmetic operations like increment (++) and decrement (--). These operations are performed based on the size of the data type the pointer is pointing to.
- Incrementing a pointer:
When you increment a pointer, it moves to the next memory location based on the size of the data type.
int arr[] = {10, 20, 30, 40}; //in arr inc & decr is not work then we use pointer
int *ptr = arr;
ptr++; // Moves the pointer to the next integer (address of arr[1])
printf("%d", *ptr); // Outputs 202. Array and Pointers
In C, arrays and pointers are closely related. The name of an array is a pointer to its first element.
#include <stdio.h>
int main() {
int arr[] = {1, 2, 3, 4};
int *ptr = arr; // Pointer points to the first element of arr
for (int i = 0; i < 4; i++) {
printf("%d ", *(ptr + i)); // Access array elements using pointer arithmetic
}
return 0;
}3. Pointer to Pointer
A pointer to a pointer stores the address of another pointer.
#include <stdio.h>
int main() {
int x = 10;
int *ptr = &x; // Pointer to int
int **pptr = &ptr; // Pointer to pointer to int
printf("%d", **pptr); // Outputs 10
return 0;
}Pointer Best Practices
Always initialize pointers with NULL:
A pointer that is not initialized will point to random memory (garbage values), leading to undefined behavior.
int *p = NULL; // It's good practice to initialize a pointer to NULL.Check for NULL before dereferencing:
Dereferencing a NULL pointer will lead to a crash or segmentation fault.
Get Musheerk’s stories in your inbox
Join Medium for free to get updates from this writer.
Avoid memory leaks:
When using dynamic memory allocation, always free memory after use to prevent memory leaks.
Interview Questions on Pointers
What is a pointer?
- A pointer is a variable that stores the memory address of another variable.
What’s the difference between * and & operators?
&gives the address of a variable, while*dereferences a pointer, accessing the value stored at the memory address.
Explain the difference between a pointer to a var and a pointer to an arr.
- A pointer to a variable stores the address of a single variable, while a pointer to an array stores the address of the first element of the array.
How do you pass a pointer to a function? Why is it useful?
- You can pass a pointer to a function by using the variable’s address (
&). This is useful for modifying the original value of a variable, rather than working with a copy.
What is a dangling pointer?
- A dangling pointer is a pointer that points to a memory location that has been freed or deallocated.
What’s the difference between a constant pointer and a pointer to a constant?
- A constant pointer cannot change the address it points to, but the value at that address can change. A pointer to a constant cannot modify the value at the address, but it can point to a different address.
Example Problem: Removing all Substrings Using Pointers
Let’s explore a practical use case where we manipulate a string using pointers. We’ll remove a substring from a given string.
#include <stdio.h>
#include <string.h>
int main() {
char str[] = "this is vectoris indiansis";
char subStr[] = "is";
int l = strlen(subStr);
char *pos;
while ((pos = strstr(str, subStr)) != NULL) {
int i = pos - str; // Find the position of the substring
for (int j = i; str[j]; j++) {
str[j] = str[j + l]; // Shift the remaining string
}
}
printf("Resultant string: %s\n", str);
return 0;
}Explanation:
- The program removes all occurrences of the substring
"is"from the string. - We use
strstr()to find the position of the substring, and pointer arithmetic (pos - str) to calculate the index. - Once we locate the substring, we shift the remaining part of the string left to overwrite it.
Memory and Pointers: Common Mistakes
- Uninitialized Pointers:
Accessing an uninitialized pointer can cause a program crash. - Dangling Pointers:
Afterfree()-ing a pointer, don’t use it until it’s re-initialized. - Buffer Overflow:
When working with arrays and pointers, ensure you don’t write past the allocated memory block. - Not freeing dynamically allocated memory:
Always free memory allocated bymalloc(),calloc(), orrealloc().
Conclusion
Pointers are a powerful tool in C, providing direct memory access and flexibility in handling data structures. However, with this power comes responsibility. Proper use of pointers requires a good understanding of memory management, pointer arithmetic, and best practices to avoid pitfalls like memory leaks and crashes.
By mastering pointers, you’ll have a deeper understanding of how memory works in C and be prepared for advanced topics like dynamic memory allocation, data structures. click here
https://medium.com/@musheerk799/understanding-dynamic-memory-allocation-in-c-39e9b2544f4b








