Pointers and Functions

Pointers are how C functions share data efficiently: output parameters, functions that modify arrays and structures in place, and functions that return pointers into existing data. This lesson collects the patterns — and the one pointer you must never return.

Output parameters

A function returns one value; pointer parameters let it produce more. The convention is to return a success flag and put results in the "out" parameters:

C
#include <stdio.h>
#include <stdbool.h>

bool parse_time(const char *text, int *hours, int *minutes) {
    int h, m;
    if (sscanf(text, "%d:%d", &h, &m) != 2) return false;
    if (h < 0 || h > 23 || m < 0 || m > 59) return false;
    *hours = h;
    *minutes = m;
    return true;
}

int main(void) {
    const char *inputs[] = { "09:45", "25:00", "noon" };
    for (int i = 0; i < 3; i++) {
        int h, m;
        if (parse_time(inputs[i], &h, &m)) {
            printf("%-6s -> %d minutes after midnight\n", inputs[i], h * 60 + m);
        } else {
            printf("%-6s -> invalid\n", inputs[i]);
        }
    }
    return 0;
}
Output
09:45  -> 585 minutes after midnight
25:00  -> invalid
noon   -> invalid

Notice the function only writes to the outputs once it knows the input is valid — so a failed call never leaves the caller's variables half-changed.

In-out parameters

A pointer parameter can be read and updated:

C
#include <stdio.h>
#include <stdbool.h>

bool withdraw(long *balance_cents, long amount_cents) {
    if (amount_cents <= 0 || amount_cents > *balance_cents) return false;
    *balance_cents -= amount_cents;
    return true;
}

int main(void) {
    long balance = 10000;   // 100.00
    printf("%s\n", withdraw(&balance, 2550) ? "ok" : "declined");
    printf("%s\n", withdraw(&balance, 9000) ? "ok" : "declined");
    printf("balance: %ld.%02ld\n", balance / 100, balance % 100);
    return 0;
}
Output
ok
declined
balance: 74.50

Returning pointers

A function may return a pointer to data that outlives the call: an element of an array the caller passed in, a string literal, a static variable, or memory from malloc:

C
#include <stdio.h>

const char *weekday_name(int day) {
    static const char *names[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
    if (day < 1 || day > 7) return "???";
    return names[day - 1];          // string literals live for the whole program
}

int *largest(int *values, size_t n) {
    int *best = &values[0];
    for (size_t i = 1; i < n; i++) {
        if (values[i] > *best) best = &values[i];
    }
    return best;                    // points into the caller's array
}

int main(void) {
    printf("%s %s\n", weekday_name(3), weekday_name(9));
    int scores[] = { 70, 95, 88 };
    *largest(scores, 3) = 100;      // modify the winner in place
    printf("%d %d %d\n", scores[0], scores[1], scores[2]);
    return 0;
}
Output
Wed ???
70 100 88

Never return a pointer to a local variable

A local variable disappears when its function returns (lesson 23). Returning its address hands back a "dangling" pointer:

C
#include <stdio.h>

char *make_greeting(const char *name) {
    char buffer[64];
    snprintf(buffer, sizeof buffer, "Hello, %s!", name);
    return buffer;
}

int main(void) {
    printf("%s\n", make_greeting("Ada"));
    return 0;
}
Compiler warnings
main.c:6:12: warning: address of stack memory associated with local variable 'buffer' returned [-Wreturn-stack-address]

Three correct alternatives: let the caller provide the buffer; allocate with malloc and make the caller free it (lesson 36); or return a struct by value. The first is the most common in C libraries:

C
#include <stdio.h>

char *make_greeting(char *buffer, size_t size, const char *name) {
    snprintf(buffer, size, "Hello, %s!", name);
    return buffer;
}

int main(void) {
    char text[64];
    printf("%s\n", make_greeting(text, sizeof text, "Ada"));
    return 0;
}
Output
Hello, Ada!

Optional parameters with NULL

Passing NULL for an output the caller doesn't need is a common convention — the function checks before writing:

C
#include <stdio.h>

int count_words(const char *s, int *longest) {
    int words = 0, best = 0, current = 0;
    for (;; s++) {
        if (*s == ' ' || *s == '\0') {
            if (current > 0) words++;
            if (current > best) best = current;
            current = 0;
            if (*s == '\0') break;
        } else {
            current++;
        }
    }
    if (longest != NULL) *longest = best;
    return words;
}

int main(void) {
    int longest;
    printf("%d words\n", count_words("a short sentence here", NULL));
    printf("%d words, ", count_words("pointers are powerful", &longest));
    printf("longest has %d letters\n", longest);
    return 0;
}
Output
4 words
3 words, longest has 8 letters

Try it yourself

Write a function that computes the mean and the standard deviation of an array, returning both through pointers.

Try it yourself · main.c
Edit the code, copy it into main.c, then compile and run it with cc -std=c17 -Wall main.c -o main && ./main. How to set up a C compiler
Output
mean 1.712 m, standard deviation 0.061 m