Passing Pointers to Functions
C passes every argument by value: the function receives a copy. That means a plain int parameter can never change the caller's variable — but a pointer parameter is a copy of an address, and following that copied address still leads back to the caller's original data. Passing pointers is how C functions modify their caller's variables, work with arrays and large structs efficiently, and produce more than one output value.
Recap: modifying a caller's variable
Passing &x to a function that takes an int * lets the function dereference that pointer to read or write the original x. This is the fundamental trick behind every "output parameter" in C, from scanf("%d", &n) to custom functions like the one below.
#include <stdio.h>
void increment(int *x) {
(*x)++; // dereference, then increment the caller's variable
}
int main(void) {
int n = 5;
increment(&n);
printf("%d\n", n);
return 0;
}6
Arrays decay to pointers when passed
An array argument is not copied when passed to a function — it decays to a pointer to its first element, so the function operates on the caller's actual array. This is efficient (no copying, even for huge arrays) but means the function must be told the length separately, since the pointer alone carries no size information.
#include <stdio.h>
void double_values(int *arr, int length) {
for (int i = 0; i < length; i++) {
arr[i] *= 2; // modifies the caller's array directly
}
}
int main(void) {
int nums[4] = {1, 2, 3, 4};
double_values(nums, 4);
for (int i = 0; i < 4; i++) {
printf("%d ", nums[i]);
}
printf("\n");
return 0;
}2 4 6 8
Passing structs by pointer avoids copying
A struct passed by value is copied field-by-field, which can be expensive for large structs and, more importantly, means the function cannot modify the caller's original. Passing a pointer to the struct avoids the copy entirely and lets the function modify the caller's data in place.
Worked example: modifying a struct through a pointer
#include <stdio.h>
typedef struct {
char name[32];
int hp;
int level;
} Character;
// Takes a pointer, so it modifies the caller's Character directly
// instead of a throwaway copy.
void level_up(Character *c) {
c->level += 1;
c->hp += 10;
}
void print_character(const Character *c) {
printf("%s: level %d, hp %d\n", c->name, c->level, c->hp);
}
int main(void) {
Character hero = {"Hero", 100, 1};
print_character(&hero);
level_up(&hero);
level_up(&hero);
print_character(&hero);
return 0;
}Hero: level 1, hp 100 Hero: level 3, hp 120
C passes arguments by value, so pointers are the mechanism for a function to modify its caller's data.
Arrays decay to a pointer when passed to a function — pass the length separately, since the pointer carries no size information.
Passing a struct by pointer avoids copying it and allows the function to modify the original.
Use
conston pointer parameters that a function only reads, never writes.