🚀 Alguni Start learning

Unit 9: Functions Deeper

Recursion, scope and sharing data.

Unit 9 of 11 in C programming for kids. Its 5 lessons are Functions That Call Themselves, Where Names Live, Passing Arrays, The String Toolkit and Function Master — below is everything each one explains, and a question or two from it to try.

Every sample on this page was compiled and run with gcc before it shipped, and prints exactly what it says it prints.

This unit opens with a fortnight’s trial of everything — no card needed — or with a family plan, bought in the iPhone app. The first two units of every track are free for ever. Try it in the app.

🪆 Functions That Call Themselves

A function may call itself

That is recursion. It needs a way to stop — the base case — and a step that gets closer to it.

C

#include <stdio.h>

void countdown(int n) {
    if (n == 0) {
        printf("Liftoff!\n");
        return;
    }
    printf("%d\n", n);
    countdown(n - 1);
}

int main() {
    countdown(3);
    return 0;
}

It prints

3
2
1
Liftoff!

Building the answer on the way back

Each call waits for the one inside it to finish, then uses that answer. factorial(4) is 4 times whatever factorial(3) works out to be.

C

#include <stdio.h>

int factorial(int n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

int main() {
    printf("%d\n", factorial(5));
    return 0;
}

It prints

120

Try it yourself

What happens without a base case?

  • It returns 0
  • It calls itself for ever until the program runs out of room and crashes
  • The compiler refuses
  • It runs once

What does this print?

C

#include <stdio.h>

int total(int n) {
    if (n == 0) {
        return 0;
    }
    return n + total(n - 1);
}

int main() {
    printf("%d\n", total(4));
    return 0;
}

Answer them in the app

🏠 Where Names Live

A variable belongs to its braces

A name declared inside a function — or inside any { } — exists only there. When the braces close, it is gone. That is why two functions can both use i without ever getting confused.

C

#include <stdio.h>

void helper(void) {
    int n = 99;
    printf("inside: %d\n", n);
}

int main() {
    int n = 1;
    helper();
    printf("outside: %d\n", n);
    return 0;
}

It prints

inside: 99
outside: 1

Even a loop has its own

A variable declared in the for header belongs to the loop. After the loop it no longer exists — which is why a total has to be declared outside it.

C

#include <stdio.h>

int main() {
    int total = 0;
    for (int i = 1; i <= 3; i++) {
        total = total + i;
    }
    printf("%d\n", total);
    return 0;
}

It prints

6

A global belongs to everyone

A variable declared outside every function can be seen and changed by all of them. Handy, but risky — when anything can change it, working out what went wrong gets hard.

C

#include <stdio.h>

int score = 0;

void add_point(void) {
    score = score + 1;
}

int main() {
    add_point();
    add_point();
    printf("%d\n", score);
    return 0;
}

It prints

2

Try it yourself

Why is passing a value in and returning it out usually better than a global?

  • It is faster
  • You can see everything the function touches from its own line — nothing changes behind your back
  • Globals are not allowed
  • It uses less memory

What does this print?

C

#include <stdio.h>

int count = 5;

void change(void) {
    int count = 100;
    count = count + 1;
}

int main() {
    change();
    printf("%d\n", count);
    return 0;
}

Answer them in the app

📦 Passing Arrays

The array itself is never copied

Give an array to a function and only its *address* is handed over. So the function works on the original — change it there and the change is real.

C

#include <stdio.h>

void zero_first(int nums[]) {
    nums[0] = 0;
}

int main() {
    int scores[3] = {7, 8, 9};
    zero_first(scores);
    printf("%d %d\n", scores[0], scores[1]);
    return 0;
}

It prints

0 8

Which is why the length must come too

Because only an address arrives, the function cannot tell how long the array is — sizeof inside it measures the pointer. Every C function that takes an array takes its length as well.

C

#include <stdio.h>

int total(int nums[], int length) {
    int sum = 0;
    for (int i = 0; i < length; i++) {
        sum = sum + nums[i];
    }
    return sum;
}

int main() {
    int scores[] = {3, 1, 4};
    int length = sizeof(scores) / sizeof(scores[0]);
    printf("%d\n", total(scores, length));
    return 0;
}

It prints

8

A single value IS copied

This is the difference that catches everyone. An int parameter is a copy, so changing it changes nothing outside — but an array parameter is a shared address.

C

#include <stdio.h>

void change_number(int n) {
    n = 99;
}

void change_array(int a[]) {
    a[0] = 99;
}

int main() {
    int n = 1;
    int a[1] = {1};
    change_number(n);
    change_array(a);
    printf("%d %d\n", n, a[0]);
    return 0;
}

It prints

1 99

Try it yourself

Why can sizeof find the length in main but not inside the function?

  • It can do both
  • main has the real array; the function only has an address, and sizeof measures that address
  • sizeof only works once
  • The array is deleted

Answer it in the app

🧵 The String Toolkit

You cannot just assign a string

A C string is an array of characters, and one array cannot be assigned to another. strcpy copies the characters across, one at a time.

C

#include <stdio.h>
#include <string.h>

int main() {
    char name[20];
    strcpy(name, "Ada");
    printf("%s\n", name);
    printf("%d\n", (int)strlen(name));
    return 0;
}

It prints

Ada
3

Joining two together

strcat sticks the second string onto the end of the first. The first has to be big enough to hold both — C will not check for you.

C

#include <stdio.h>
#include <string.h>

int main() {
    char full[30];
    strcpy(full, "Ada");
    strcat(full, " Lovelace");
    printf("%s\n", full);
    printf("%d\n", (int)strlen(full));
    return 0;
}

It prints

Ada Lovelace
12

Comparing needs a function too

== on strings compares *addresses*, not letters, so it is almost never what you want. strcmp returns 0 when they match — which reads backwards at first, so it is worth remembering as "no difference".

C

#include <stdio.h>
#include <string.h>

int main() {
    char password[20];
    strcpy(password, "let-me-in");
    if (strcmp(password, "let-me-in") == 0) {
        printf("Welcome!\n");
    } else {
        printf("Wrong\n");
    }
    return 0;
}

It prints

Welcome!

Less than zero means "comes first"

When they differ, strcmp tells you which comes first alphabetically — negative for the first, positive for the second. That is how you sort words in C.

C

#include <stdio.h>
#include <string.h>

int main() {
    printf("%d\n", strcmp("apple", "banana") < 0);
    printf("%d\n", strcmp("banana", "apple") < 0);
    return 0;
}

It prints

1
0

Try it yourself

What does strcmp(a, b) == 0 mean?

  • a is empty
  • The two strings are exactly the same
  • a comes first alphabetically
  • They are different

Answer it in the app

🏆 Function Master

Try it yourself

What does this print?

C

#include <stdio.h>

int mystery(int n) {
    if (n <= 0) {
        return 0;
    }
    return n + mystery(n - 2);
}

int main() {
    printf("%d\n", mystery(6));
    return 0;
}

Answer it in the app