Character pointers extend beyond simple variable addressing to handle string literals efficiently. When assigning a string literal to a pointer, the memory address of the first character is stored. Since string literals reside in read-only memory, qualifying the pointer with const prevents accidental modification.
#include <stdio.h>
int main(void) {
const char *str_handle = "HelloWorld";
puts(str_handle);
printf("First char: %c\n", *str_handle);
return 0;
}
Arrays of Pointers
When an array is designed to hold memory addresses rather than primitive values, its classified as a pointer array. The syntax places the brackets higher in precedence than the dereference operator, indicating an array of pointers.
int *value_refs[10]; // Array holding 10 integer pointers
double *math_ptrs[5]; // Array holding 5 double pointers
Pointers to Arrays
Distinct from an array of pointers, a pointer to an array holds the address of an entire contiguous block. Declaration requires parentheses to enforce precedence, ensuring the pointer targets the array type rather than a single element.
int (*grid_ptr)[4]; // Pointer to an array of 4 integers
Understanding Array Identifiers
Generally, an array identifier decays to the address of its first element. How ever, two specific contexts preserve the whole array type:
- When used with the
sizeofoperator, it returns the total byte size of the array. - When preceded by the address-of operator (
&), it yields the address of the entire array structure.
Utilizing Array Pointers with Matrices
Array pointers are particularly effective when passing multi-dimensional arrays to functions. A 2D array name passed to a function decays to a pointer to its first row. The function parameter must match this type to perform correct arithmetic.
#include <stdio.h>
void render_matrix(int (*matrix)[4], int rows, int cols) {
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
int val = *(*(matrix + r) + c);
printf("%d ", val);
}
printf("\n");
}
}
int main(void) {
int data[2][4] = {
{10, 20, 30, 40},
{50, 60, 70, 80}
};
render_matrix(data, 2, 4);
return 0;
}
When defining function parameters for 2D arrays, the column size must be specified in the array syntax, whereas the row count can be omitted. Alternatively, using an explicit array pointer type ensures type safety.
Function Pointers
Functions occupy specific memory locations during execution, allowing their entry points to be assigned to pointer variables. This enables dynamic function invocation and callback mechanisms.
Syntax and Declaration
The declaration mirrors the function signature, replacing the function name with a pointer variable enclosed in parentheses.
void log_message(int code);
// Declaration of a function pointer
void (*action_ptr)(int) = &log_message;
// Invocation
action_ptr(100);
Practical Applications
Function pointers facilitate decoupling logic, allowing algorithms to accept behavior as arguments. They are essential for implementing state machines, event handlers, and polymorphism-like structures in C. The address-of operator is optional when assigning a function to a pointer, as the function name implicitly converts to its address.