Pointers
Understanding pointers, memory addresses, and pointer arithmetic. Using pointers to access and manipulate variables and arrays.
Pointers and Arrays in C Programming
Understanding Pointers
A pointer is a variable that stores the memory address of another variable. Think of it like a street address; it tells you where to find something (a variable's value) in memory. In C, pointers are declared using the asterisk (*) symbol.
Example:
#include <stdio.h>
int main() {
int num = 10; // Declare an integer variable
int *ptr; // Declare a pointer to an integer
ptr = # // Assign the address of 'num' to 'ptr'
printf("Value of num: %d\n", num);
printf("Address of num: %p\n", &num);
printf("Value of ptr: %p\n", ptr); // ptr holds the address of num
printf("Value pointed to by ptr: %d\n", *ptr); // Dereferencing ptr to get the value of num
return 0;
}
In this example:
- `int num = 10;` declares an integer variable `num` and initializes it with the value 10.
- `int *ptr;` declares a pointer variable `ptr` that can store the address of an integer variable.
- `ptr = #` assigns the address of `num` to `ptr`. The `&` operator (address-of operator) returns the memory address of a variable.
- `*ptr` is used to access the value stored at the memory address pointed to by `ptr`. This is called "dereferencing" the pointer.
Understanding Arrays
An array is a contiguous block of memory locations, all holding values of the same data type. Arrays provide a way to store and access multiple values of the same type using a single variable name. Array elements are accessed using an index, starting from 0.
Example:
#include <stdio.h>
int main() {
int numbers[5] = {1, 2, 3, 4, 5}; // Declare an integer array of size 5
printf("Element at index 0: %d\n", numbers[0]);
printf("Element at index 2: %d\n", numbers[2]);
return 0;
}
In this example:
- `int numbers[5];` declares an integer array named `numbers` that can hold 5 integer values.
- `{1, 2, 3, 4, 5}` initializes the array elements with the specified values.
- `numbers[0]` accesses the first element of the array (at index 0). `numbers[2]` accesses the third element (at index 2).
The Relationship Between Pointers and Arrays
In C, there is a very strong relationship between pointers and arrays. Specifically, the name of an array, when used without an index, decays into a pointer to the first element of the array. This means that `numbers` (from the previous example) is equivalent to `&numbers[0]`.
This has important implications:
- You can use pointer arithmetic to access array elements.
- You can pass arrays to functions as pointers.
Array Names as Pointers
Consider this code:
#include <stdio.h>
int main() {
int numbers[5] = {10, 20, 30, 40, 50};
int *ptr;
ptr = numbers; // Assign the address of the first element of 'numbers' to 'ptr'
printf("Value of numbers[0]: %d\n", numbers[0]);
printf("Address of numbers[0]: %p\n", &numbers[0]);
printf("Value of ptr: %p\n", ptr); // ptr holds the same address as &numbers[0]
printf("Value pointed to by ptr: %d\n", *ptr); // Dereferencing ptr gives numbers[0]
return 0;
}
As you can see, `ptr` now points to the first element of the `numbers` array.
Pointer Arithmetic
Pointer arithmetic allows you to manipulate pointers by adding or subtracting integer values. When you add an integer `n` to a pointer, the pointer is incremented by `n` times the size of the data type it points to.
For example, if `ptr` is an `int*` (pointer to an integer), `ptr + 1` will point to the next integer in memory.
Here's how you can access array elements using pointer arithmetic:
#include <stdio.h>
int main() {
int numbers[5] = {10, 20, 30, 40, 50};
int *ptr;
ptr = numbers; // Point to the first element
printf("Value of numbers[0]: %d\n", *ptr);
printf("Value of numbers[1]: %d\n", *(ptr + 1)); // Access the second element
printf("Value of numbers[2]: %d\n", *(ptr + 2)); // Access the third element
return 0;
}
In this example:
- `*(ptr + 1)` is equivalent to `numbers[1]`. It dereferences the pointer at the address `ptr + (1 * sizeof(int))`.
- `*(ptr + 2)` is equivalent to `numbers[2]`. It dereferences the pointer at the address `ptr + (2 * sizeof(int))`.
Important Considerations
- **Bounds Checking:** C does *not* perform bounds checking on arrays. It's your responsibility to ensure that you don't access elements outside the valid range of the array (0 to size-1). Accessing elements out of bounds can lead to unpredictable behavior and crashes.
- **Pointer Increment/Decrement:** You can also use the `++` and `--` operators to increment and decrement pointers. For example, `ptr++` will increment `ptr` to point to the next element in memory.
- **Array vs. Pointer:** While the array name decays to a pointer, there are subtle differences. The array name is *not* a modifiable lvalue. You can't assign a new address to the array name (e.g., `numbers = another_array;` is invalid). The array name is bound to the memory allocated to it. Pointers are variables and can be reassigned to different addresses.
Passing Arrays to Functions
When you pass an array to a function in C, you're actually passing a pointer to the first element of the array. The function doesn't receive a copy of the entire array. This means that changes made to the array elements within the function will affect the original array.
#include <stdio.h>
void modify_array(int *arr, int size) {
for (int i = 0; i < size; i++) {
arr[i] = arr[i] * 2; // Double each element
}
}
int main() {
int numbers[5] = {1, 2, 3, 4, 5};
printf("Original array: ");
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
modify_array(numbers, 5); // Pass the array (as a pointer) to the function
printf("Modified array: ");
for (int i = 0; i < 5; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}
In this example:
- The `modify_array` function takes a pointer `int *arr` and the size of the array as arguments.
- Inside the function, the elements of the array are modified. Because `arr` points to the same memory location as `numbers` in `main`, the original `numbers` array is changed.