Pointers & Memory
Pointers, Arrays & Functions
Call by reference, the swap function, returning several results, how arrays decay to pointers, and pointers to strings.
Call by reference
Functions receive copies of their arguments. To let a function change the caller's variable, pass its address, and have the function write through the pointer:
#include <stdio.h>
void swapWrong(int a, int b) { int t = a; a = b; b = t; }
void swap(int *a, int *b) { int t = *a; *a = *b; *b = t; }
int main(void) {
int x = 3, y = 8;
swapWrong(x, y);
printf("after swapWrong: x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("after swap: x = %d, y = %d\n", x, y);
return 0;
}after swapWrong: x = 3, y = 8 after swap: x = 8, y = 3
Returning several results
A function can return only one value, but it can fill as many variables as you give it addresses of:
#include <stdio.h>
void stats(const int a[], int n, int *min, int *max, double *avg) {
*min = *max = a[0];
int sum = 0;
for (int i = 0; i < n; i++) {
if (a[i] < *min) *min = a[i];
if (a[i] > *max) *max = a[i];
sum += a[i];
}
*avg = (double)sum / n;
}
int main(void) {
int marks[] = {67, 91, 54, 78, 85};
int lo, hi;
double mean;
stats(marks, 5, &lo, &hi, &mean);
printf("min %d, max %d, average %.1f\n", lo, hi, mean);
return 0;
}min 54, max 91, average 75.0
scanf("%d", &n) works exactly this way — now you know why it needs &.
Arrays and pointers
An array's name, used in an expression, decays to a pointer to its first element. These are all equivalent:
| Array notation | Pointer notation |
|---|---|
a[i] |
*(a + i) |
&a[i] |
a + i |
a[0] |
*a |
#include <stdio.h>
int sum(int *p, int n) { // same as int p[]
int s = 0;
for (int i = 0; i < n; i++) s += *(p + i);
return s;
}
int main(void) {
int a[] = {5, 10, 15, 20};
printf("a[2] = %d, *(a + 2) = %d, 2[a] = %d\n", a[2], *(a + 2), 2[a]);
printf("sum = %d\n", sum(a, 4));
printf("sum of last two = %d\n", sum(a + 2, 2)); // pass part of an array
return 0;
}a[2] = 15, *(a + 2) = 15, 2[a] = 15 sum = 50 sum of last two = 35
(2[a] works because a[i] is defined as *(a + i), and addition does not care about order. Fun fact, never write it in real code.)
Pointers and strings
A string literal can be referenced by a char *. Walking a string with a pointer is a very common C idiom:
#include <stdio.h>
int length(const char *s) {
const char *start = s;
while (*s) s++; // stop at '\0'
return (int)(s - start);
}
void toUpper(char *s) {
for (; *s; s++)
if (*s >= 'a' && *s <= 'z') *s -= 32;
}
int main(void) {
char word[] = "pointer";
printf("length = %d\n", length(word));
toUpper(word);
printf("upper = %s\n", word);
const char *greeting = "hello"; // points to read-only memory
printf("%c%c\n", *greeting, *(greeting + 4));
return 0;
}length = 7 upper = POINTER ho
Arrays of pointers
An array of char * is the usual way to store a list of strings of different lengths:
#include <stdio.h>
#include <string.h>
int main(void) {
const char *subjects[] = {"C", "Data Structures", "Discrete Mathematics", "Python"};
int n = sizeof(subjects) / sizeof(subjects[0]);
for (int i = 0; i < n; i++)
printf("%d. %s (%zu chars)\n", i + 1, subjects[i], strlen(subjects[i]));
return 0;
}1. C (1 chars) 2. Data Structures (15 chars) 3. Discrete Mathematics (20 chars) 4. Python (6 chars)
Function pointers
Functions have addresses too. A function pointer lets you pass behaviour as an argument — this is how qsort lets you choose the sort order:
#include <stdio.h>
#include <stdlib.h>
int ascending(const void *a, const void *b) { return *(const int *)a - *(const int *)b; }
int descending(const void *a, const void *b) { return *(const int *)b - *(const int *)a; }
void show(const int *a, int n) { for (int i = 0; i < n; i++) printf("%d ", a[i]); printf("\n"); }
int main(void) {
int a[] = {42, 7, 19, 3, 88, 25};
int n = 6;
qsort(a, n, sizeof(int), ascending);
show(a, n);
qsort(a, n, sizeof(int), descending);
show(a, n);
int (*op)(const void *, const void *) = ascending; // a variable holding a function
printf("op(&a[0], &a[1]) = %d\n", op(&a[0], &a[1]) > 0);
return 0;
}3 7 19 25 42 88 88 42 25 19 7 3 op(&a[0], &a[1]) = 1
Test yourself
4 questions · pick an answer to check it instantly
- 1
Which call lets
void inc(int *p) { (*p)++; }changeninmain?The function needsn's address, written&n. - 2
For
int a[5];, which expression is the same asa[3]?a[i]is defined as*(a + i).*a + 3adds 3 to the first element's value. - 3
Why does
char *s = "hi"; s[0] = 'H';usually crash?Usechar s[] = "hi";to get a writable copy on the stack. - 4
Inside
void f(int a[]), what doessizeof(a)give on a 64-bit machine?The array decays to a pointer when passed, so the function only has an address.