Pointer Basics (* / &)
| Since: | C89(1989) |
|---|
A pointer is a variable that stores the memory address of another variable. Use the & operator to get an address, and the * operator to read or write the value at that address. Pointers are a core feature of C and are fundamental to arrays, strings, dynamic memory, and function pointers.
Syntax
// Declares a pointer variable (a pointer to the specified type). type *pointerName; // Gets the address of a variable (address-of operator). &variableName // Reads or writes the value at the address the pointer points to (dereference operator). *pointerName // Declares and initializes a pointer at the same time. type *pointerName = &variableName; // Null pointer (represents a pointer that points to nothing). type *pointerName = NULL;
Pointer Operators
| Operator | Name | Description |
|---|---|---|
| & | Address-of operator | Returns the memory address of a variable. Used to assign to a pointer or pass to a function. |
| * (in declaration) | Pointer declaration | Indicates that a variable is a pointer. Written after the type name. |
| * (in expression) | Dereference operator | Reads or writes the value at the address the pointer points to. Also called dereferencing. |
| NULL | Null pointer constant | Represents a pointer that does not point to any address. Used to initialize pointers or indicate an invalid state. |
Sample Code
double_value() modifies the caller's variable through a pointer. swap() swaps the values of two variables.
pointer_basic.c
#include <stdio.h>
void double_value(int *p) {
*p = *p * 2; // Doubles the value at the address the pointer points to.
}
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main(void) {
int x = 10;
int *p = &x; // Stores the address of x in p.
printf("Value of x: %d\n", x); // Prints '10'.
printf("Address of x: %p\n", (void *)&x);
printf("Value of p (address): %p\n", (void *)p);
printf("Value p points to: %d\n", *p); // Prints '10'.
// Modifies the value through the pointer.
*p = 20;
printf("x after modification: %d\n", x); // Prints '20'.
// Passes a pointer to a function to modify the value.
double_value(&x);
printf("x after doubling: %d\n", x); // Prints '40'.
// Swapping values.
int a = 5, b = 9;
swap(&a, &b);
printf("a = %d, b = %d\n", a, b); // Prints 'a = 9, b = 5'.
// Example of a NULL check.
int *q = NULL;
if (q == NULL) {
printf("The pointer is NULL.\n");
}
return 0;
}
gcc pointer_basic.c -o pointer_basic ./pointer_basic Value of x: 10 Address of x: 0x... Value of p (address): 0x... Value p points to: 10 x after modification: 20 x after doubling: 40 a = 9, b = 5 The pointer is NULL.
Pointers and Arrays
In C, an array name is treated as a pointer to its first element. Pointers and arrays differ in notation, but internally they use the same address arithmetic.
pointer_array_demo.c
#include <stdio.h>
int main(void) {
int scores[5] = {85, 92, 78, 95, 88};
int *p = scores; // 'scores' is equivalent to '&scores[0]'.
// Pointers and arrays refer to the same elements.
printf("scores[2] = %d\n", scores[2]); // 78
printf("*(p + 2) = %d\n", *(p + 2)); // 78 (pointer arithmetic)
printf("p[2] = %d\n", p[2]); // 78 (array notation)
// Loop through an array using a pointer.
for (int i = 0; i < 5; i++) {
printf("%d ", *(p + i)); // 85 92 78 95 88
}
printf("\n");
// Strings can also be handled with pointers.
const char *name = "Kusanagi Kyo";
printf("%s\n", name); // Kusanagi Kyo
return 0;
}
gcc pointer_array_demo.c -o pointer_array_demo ./pointer_array_demo scores[2] = 78 *(p + 2) = 78 p[2] = 78 85 92 78 95 88 Kusanagi Kyo
For more details on pointers and arrays, see Pointers and Arrays.
Double Pointers (Pointer to a Pointer)
A double pointer (double indirection) holds the address of a pointer variable. It is used when a function needs to modify the caller's pointer—for example, to allocate memory inside a function.
double_pointer.c
#include <stdio.h>
#include <stdlib.h>
// Initializes the caller's pointer inside the function.
void init_array(int **pp, int size) {
*pp = malloc(sizeof(int) * size);
if (*pp == NULL) return;
for (int i = 0; i < size; i++) {
(*pp)[i] = (i + 1) * 10;
}
}
int main(void) {
int *arr = NULL;
init_array(&arr, 5); // Pass the address of 'arr' to let the function initialize it.
if (arr == NULL) { return 1; }
for (int i = 0; i < 5; i++) {
printf("%d ", arr[i]); // 10 20 30 40 50
}
printf("\n");
free(arr);
arr = NULL;
return 0;
}
gcc double_pointer.c -o double_pointer ./double_pointer 10 20 30 40 50
Common mistake 1: dereferencing an uninitialized pointer
Dereferencing an uninitialized pointer causes undefined behavior (runtime crash). Always initialize a pointer to NULL when you declare it.
uninitialized_ptr_ng.c
// NG: Dereferencing an uninitialized pointer (undefined behavior). int *p; *p = 42; // Causes a crash.
gcc -o uninitialized_ptr_ng uninitialized_ptr_ng.c ./uninitialized_ptr_ng Segmentation fault (core dumped)
// OK: Always initialize to NULL before use.
int *p = NULL;
if (p != NULL) {
*p = 42; // Use only after a NULL check.
}
Common mistake 2: dangling pointer
Using a dangling pointer (a pointer to freed memory) causes undefined behavior. Always assign NULL after freeing.
// NG: Using a dangling pointer (pointer to freed memory). int *q = malloc(sizeof(int)); free(q); *q = 99; // Memory is already freed — undefined behavior.
// OK: Assign NULL after freeing. free(q); q = NULL; // Prevents a dangling pointer.
Notes
In C, function arguments are passed by value (copied) by default. To modify a variable inside a function, pass a pointer to it. The function can then write to that address to change the caller's variable.
Dereferencing an uninitialized pointer or a pointer to freed memory causes crashes and undefined behavior. Initializing pointers when you declare them and assigning NULL after use helps avoid undefined behavior.
For the relationship between pointers and arrays, see Pointers and Arrays. For dynamic memory allocation and deallocation, see malloc() / free().
If you find any errors or copyright issues, please contact us.