Skip to content

Intermediate · Pointers · topic 22 of 60 · 30 min

Pointers and functions

Explanation

Because C passes arguments by value, a function can only change a caller's variable if it receives that variable's address. Passing &x lets swap, scanf and "return several results" functions write to the caller's variables. Never return the address of a local variable. const int *p means "cannot change what p points to"; int *const p means "p cannot point elsewhere".

The swap that does not work

output
void swap_wrong(int a, int b) { int t = a; a = b; b = t; }

int main(void) {
    int x = 1, y = 2;
    swap_wrong(x, y);
    printf("%d %d\n", x, y);    /* 1 2: nothing changed */
}

main's frame          swap_wrong's frame
x: 1   y: 2           a: 1 → 2   b: 2 → 1   (copies, thrown away on return)

The swap that works

c
void swap(int *a, int *b) {
    int t = *a;      /* value at a */
    *a = *b;         /* write into the caller's variable */
    *b = t;
}

int main(void) {
    int x = 1, y = 2;
    swap(&x, &y);                 /* pass the ADDRESSES */
    printf("%d %d\n", x, y);      /* 2 1 */
}
output
before the call:              inside swap:
0x100  x: 1                   a: 0x100 ──► x
0x104  y: 2                   b: 0x104 ──► y
                              t = *a (1); *a = *b (x = 2); *b = t (y = 1)
after: x: 2   y: 1
The pointers themselves are copies, but they carry the real addresses.

Returning several results

c
void min_max(const int a[], int n, int *min, int *max) {
    *min = *max = a[0];
    for (int i = 1; i < n; i++) {
        if (a[i] < *min) *min = a[i];
        if (a[i] > *max) *max = a[i];
    }
}

int lo, hi;
int temps[] = {31, 28, 36, 33};
min_max(temps, 4, &lo, &hi);    /* lo = 28, hi = 36 */
These are called output parameters. scanf("%d", &n) works the same way.

Never return the address of a local

c
int *bad(void) {
    int total = 100;
    return &total;          /* total dies when bad() returns: a dangling pointer */
}
int *p = bad();
printf("%d\n", *p);         /* undefined behaviour: may print 100, garbage, or crash */
gcc warns: "function returns address of local variable". Return a value instead, or memory from malloc (module 6), or a static/global.

const and pointers

DeclarationCan change *p?Can change p?Use
int *pYesYesNormal pointer
const int *p (= int const *p)NoYesRead-only access (most function parameters)
int *const pYesNoA fixed pointer (like a hardware register)
const int *const pNoNoFixed and read-only

Read declarations from right to left: int *const p is "p is a const pointer to int"; const int *p is "p is a pointer to an int that is const". Mark pointer parameters const whenever the function only reads, like size_t strlen(const char *s).

Careful: Passing a NULL or uninitialised pointer to a function that writes through it (min_max(a, n, NULL, &hi)) crashes. Document which pointer parameters may be NULL, and check them in public functions: if (!min || !max) return -1;.
Think of it like this: Passing a value is like giving a friend a photocopy of your marksheet: they can scribble on it, but your original is safe. Passing a pointer is like giving them the key to your cupboard: now they can change what is inside. const on the pointer is like giving a key that opens the glass door to look, but not the lock to take things out.
Tip: If a function must change several of the caller's variables, consider returning a struct instead (module 7); it is often clearer than many output pointers.

Need help?

Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.

Try:

Watch the lesson

Pointers and functions · 1/6

Pointers and functions

In this lesson you will let functions change the caller's variables using pointers.

Prefer a video by a teacher? Find free videos on “c pointers functions swap call by reference const pointer” on YouTube ↗

In real life: Splitting a bill into rupees and paise

A billing library has a function that converts a total in paise into rupees and paise for printing. It returns both parts through output pointers, and returns an error code if the amount is negative, which is a common C style.

c
int split_amount(long paise, long *rupees, int *rest) {
    if (paise < 0 || !rupees || !rest) return -1;
    *rupees = paise / 100;
    *rest = (int)(paise % 100);
    return 0;
}

long r; int p;
if (split_amount(149950, &r, &p) == 0) printf("Rs %ld.%02d\n", r, p);   /* Rs 1499.50 */

Practice (0/3 done)

Task 1 · Question

What does this print? void f(int *p) { *p = *p * 2; p = NULL; } … int x = 7; int *q = &x; f(q); printf("%d %d\n", x, q == &x);

Task 2 · Question

Which declaration lets the function READ the int but not change it?

Task 3 · Practice

Write void stats(const int a[], int n, int *sum, double *avg, int *count_above_avg) that returns three results through pointers, and int safe_div(int a, int b, int *result) that returns -1 for b == 0 and 0 otherwise. Draw the memory diagram for one call of safe_div.

Quick quiz

Question 1

1.Why does scanf("%d", &n) need &n?

Question 2

2.Returning &local from a function gives…

Question 3

3.int *const p = &x; Which is allowed?

Question 4

4.How many values can a C function return directly with return?

Read more (free)

Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.

Why does scanf("%d", &n) need &n?

Answer: So scanf can write the value into n through its address

scanf writes through the pointer.

Returning &local from a function gives…

Answer: A dangling pointer to memory that is no longer valid

The local variable is gone after return.

int *const p = &x; Which is allowed?

Answer: *p = 5;

p itself is const, but the int it points to is not.

How many values can a C function return directly with return?

Answer: One

Use pointers or structs for more.

What is wrong with: const std::string& name() { std::string s = "Asha"; return s; }Related

Answer: It returns a reference to a local that is destroyed: a dangling reference

s dies when the function returns. Return std::string by value.

From References: another name for a variable

Is it safe to return &local from a function?Related

Answer: Yes, the compiler moves it to the heap if needed

Escape analysis keeps the value alive as long as it is referenced.

From Pointers without fear

A non-void function ends without return on one branch, and the caller uses the result. This is…Related

Answer: Undefined behaviour

gcc -Wall warns about it.

From Functions

How should a pointer be printed with printf?Related

Answer: %p with a (void *) cast

%p expects a void pointer.

From Addresses and pointers

Pass the quiz (60% or more) or mark this topic as done when you are ready.

Your progress is saved on this device only.

Next steps

  1. 3 more topics in “Pointers” before its exam: Pointers and arrays, Pointer arithmetic, NULL, dangling pointers and pointers to pointers.
  2. Module 5 exam: Pointers · 12 questions · 25 min, without help. 5 topics of this module still to finish first.
  3. Then the next module, Dynamic memory. 60 topics left in the course before the final exam.

← Previous: Addresses and pointers