Pointers
## Learning Objectives
- Understand pointer basics
- Master pointer operations
- Work with pointers and arrays
- Learn pointer arithmetic
## What is a Pointer?
A pointer is a variable that stores the memory address of another variable.
```c
int x = 10;
int *ptr = &x; // ptr holds address of x
printf("%d\n", x); // Value of x: 10
printf("%p\n", ptr); // Address of x
printf("%d\n", *ptr); // Value at address: 10
```
## Pointer Declaration
### Syntax
```c
int *ptr; // Pointer to int
char *cptr; // Pointer to char
float *fptr; // Pointer to float
double *dptr; // Pointer to double
```
### Common Confusion
```c
int *p1, p2; // p1 is pointer, p2 is int (not both!)
int *p1, *p2; // Both are pointers
```
## Address Operator (&)
```c
int x = 10;
int *ptr = &x; // &x gives address of x
printf("Address of x: %p\n", &x);
printf("ptr contains: %p\n", ptr);
```
## Dereference Operator (*)
```c
int x = 10;
int *ptr = &x;
printf("%d\n", *ptr); // 10 (value at address)
*ptr = 20; // Modify value through pointer
printf("%d\n", x); // 20 (x is now 20)
```
## NULL Pointer
### Declaration
```c
int *ptr = NULL; // Good practice - initialize to NULL
```
### Check Before Use
```c
int *ptr = NULL;
if (ptr != NULL) {
printf("%d\n", *ptr);
}
```
### Uninitialized vs NULL
```c
int *p1; // Uninitialized - garbage value
int *p2 = NULL; // NULL pointer - safe to check
```
## Pointers and Arrays
### Array Name as Pointer
```c
int arr[] = {1, 2, 3, 4, 5};
int *ptr = arr; // arr decays to pointer to first element
printf("%d\n", *ptr); // 1 (first element)
printf("%d\n", *(ptr + 1)); // 2 (second element)
```
### Equivalence
```c
arr[i] == *(arr + i)
&arr[i] == arr + i
```
### Array Index with Pointer
```c
int arr[] = {10, 20, 30};
int *ptr = arr;
printf("%d\n", ptr[0]); // 10
printf("%d\n", ptr[1]); // 20
```
## Pointer Arithmetic
### Increment/Decrement
```c
int arr[] = {10, 20, 30};
int *ptr = arr;
ptr++; // Move to next int
printf("%d\n", *ptr); // 20
ptr--; // Move to previous int
printf("%d\n", *ptr); // 10
```
### Addition/Subtraction
```c
int arr[] = {10, 20, 30, 40, 50};
int *ptr = arr;
printf("%d\n", *(ptr + 2)); // 30
printf("%d\n", *(ptr + 4)); // 50
ptr = &arr[4];
printf("%d\n", *(ptr - 2)); // 30
```
### Difference Between Pointers
```c
int arr[] = {10, 20, 30, 40, 50};
int *p1 = &arr[0];
int *p2 = &arr[4];
ptrdiff_t diff = p2 - p1; // 4
```
## Pointers and Functions
### Pass by Reference
```c
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main(void) {
int x = 10, y = 20;
swap(&x, &y);
printf("%d %d\n", x, y); // 20 10
return 0;
}
```
### Array Parameter
```c
int sum(int *arr, int size) {
int total = 0;
for (int i = 0; i < size; i++) {
total += arr[i]; // or *(arr + i)
}
return total;
}
int main(void) {
int nums[] = {1, 2, 3, 4, 5};
printf("%d\n", sum(nums, 5)); // 15
return 0;
}
```
## const with Pointers
### Pointer to const
```c
const int x = 10;
const int *ptr = &x;
// *ptr = 20; // Error! Cannot modify through pointer
```
### const Pointer
```c
int x = 10;
int y = 20;
int *const ptr = &x;
*ptr = 30; // OK - can modify value
// ptr = &y; // Error! Cannot change where ptr points
```
### const Pointer to const
```c
const int x = 10;
const int *const ptr = &x;
// Cannot modify value or change address
```
## Pointer to Pointer
```c
int x = 10;
int *p1 = &x;
int **p2 = &p1; // Pointer to pointer
printf("%d\n", **p2); // 10
```
### Use Case: Modify pointer in function
```c
void allocate(int **ptr) {
*ptr = malloc(sizeof(int));
**ptr = 42;
}
int main(void) {
int *p = NULL;
allocate(&p);
printf("%d\n", *p); // 42
free(p);
return 0;
}
```
## void Pointer
### Generic Pointer
```c
void *ptr; // Can point to any type
int x = 10;
double y = 3.14;
ptr = &x;
// printf("%d\n", *ptr); // Error! Cannot dereference void*
printf("%d\n", *(int*)ptr); // Cast to int*
ptr = &y;
printf("%f\n", *(double*)ptr); // Cast to double*
```
### Use with malloc
```c
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
```
## Dynamic Memory (malloc/free)
```c
#include
int *ptr = (int*)malloc(sizeof(int));
if (ptr == NULL) {
// Allocation failed
return 1;
}
*ptr = 42;
printf("%d\n", *ptr);
free(ptr); // Release memory
ptr = NULL; // Avoid dangling pointer
```
## Pointers to Functions
```c
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int main(void) {
int (*operation)(int, int);
operation = add;
printf("%d\n", operation(5, 3)); // 8
operation = subtract;
printf("%d\n", operation(5, 3)); // 2
return 0;
}
```
## Common Pitfalls
### Dangling Pointer
```c
int *ptr = malloc(sizeof(int));
free(ptr);
// ptr still points to freed memory - BAD!
ptr = NULL; // Always set to NULL after free
```
### Double Free
```c
free(ptr);
free(ptr); // Undefined behavior!
```
### Memory Leak
```c
int *ptr = malloc(sizeof(int));
ptr = malloc(sizeof(int)); // First allocation leaked
free(ptr);
```
### Uninitialized Pointer
```c
int *ptr;
// *ptr = 10; // Undefined! Points to garbage
ptr = malloc(sizeof(int)); // Initialize first
*ptr = 10;
free(ptr);
```
## Summary
- Pointers store memory addresses
- `*` declares pointer and dereferences
- `&` gets address of a variable
- NULL is safe; uninitialized is dangerous
- Array name decays to pointer
- Pointer arithmetic: `ptr + n`, `ptr - n`
- Use `const` to prevent modification
- `void*` can point to any type
- Always `free()` dynamically allocated memory
- Set pointers to NULL after freeing
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →