homework.wenqian.dev
← Back to index
Week 22026-05-28

Functions

Week 1 Review · Function Syntax · void Functions · Scope

Part 1 — Week 1 Homework Review

Before we move on, let's walk through clean solutions to the three problems from last week. Pay attention to how similar the structure is across the three problems — that's a clue for what we'll learn today.

Problem 1 — GCD

Two ways to solve this. The first works but is slow when numbers are large; the second is the classic Euclidean algorithm.

Approach 1 — Brute force (loop from 1 to min(a, b))

gcd.c (brute force)
#include <stdio.h>int main() {    int a, b;    scanf("%d %d", &a, &b);    int result = 1;    int min = (a < b) ? a : b;    for (int i = 1; i <= min; i++) {        if (a % i == 0 && b % i == 0) {            result = i;        }    }    printf("%d\n", result);    return 0;}

Approach 2 — Euclidean algorithm (much faster)

Idea: GCD(a, b) = GCD(b, a mod b). Keep replacing the pair until the second number becomes 0; the first one is the answer.

gcd.c (Euclidean)
#include <stdio.h>int main() {    int a, b;    scanf("%d %d", &a, &b);    while (b != 0) {        int r = a % b;        a = b;        b = r;    }    printf("%d\n", a);    return 0;}

Python version (Euclidean)

gcd.py
a, b = map(int, input().split())while b != 0:    a, b = b, a % bprint(a)
Key idea: If you wanted to compute the GCD of 5 different pairs of numbers, you'd have to copy the whole while loop 5 times. That's exactly the problem functions solve.

Problem 2 — Prime Number Check

The key optimization: we only need to check divisors up to √n. Use i * i <= n in the loop condition. Also notice the use of break to exit the loop early once we've found a divisor.

prime.c
#include <stdio.h>int main() {    int n;    scanf("%d", &n);    int is_prime = 1;    for (int i = 2; i * i <= n; i++) {        if (n % i == 0) {            is_prime = 0;            break;        }    }    printf("%s\n", is_prime ? "YES" : "NO");    return 0;}
prime.py
n = int(input())is_prime = Truei = 2while i * i <= n:    if n % i == 0:        is_prime = False        break    i += 1print("YES" if is_prime else "NO")
Key idea: break jumps out of the nearest enclosing loop. Use it whenever there's no point continuing — like "I found a divisor, so n is definitely not prime."

Problem 3 — Perfect Number

Loop through all numbers from 1 to n−1, sum the divisors, then compare with n.

perfect.c
#include <stdio.h>int main() {    int n;    scanf("%d", &n);    int sum = 0;    for (int i = 1; i < n; i++) {        if (n % i == 0) {            sum += i;        }    }    printf("%s\n", sum == n ? "YES" : "NO");    return 0;}
perfect.py
n = int(input())total = 0for i in range(1, n):    if n % i == 0:        total += iprint("YES" if total == n else "NO")
Key idea: Look at all three solutions side by side — they all follow the pattern: read input → run a loop → compute an answer → print it. The "run a loop and compute" part is a self-contained operation. That's a function waiting to be born.

Part 2 — Functions

1. Why do we need functions?

Suppose you want to compute the GCD of three pairs of numbers and print all three results. Without functions:

without_functions.c
#include <stdio.h>int main() {    // GCD of (12, 18)    int a1 = 12, b1 = 18;    while (b1 != 0) { int r = a1 % b1; a1 = b1; b1 = r; }    printf("%d\n", a1);    // GCD of (100, 75) — same logic, copied!    int a2 = 100, b2 = 75;    while (b2 != 0) { int r = a2 % b2; a2 = b2; b2 = r; }    printf("%d\n", a2);    // GCD of (7, 13) — copied again!    int a3 = 7, b3 = 13;    while (b3 != 0) { int r = a3 % b3; a3 = b3; b3 = r; }    printf("%d\n", a3);    return 0;}

With a function, the same program becomes:

with_function.c
#include <stdio.h>int gcd(int a, int b) {    while (b != 0) {        int r = a % b;        a = b;        b = r;    }    return a;}int main() {    printf("%d\n", gcd(12, 18));    printf("%d\n", gcd(100, 75));    printf("%d\n", gcd(7, 13));    return 0;}
Key idea: A function is a reusable block of code with a name. Write the logic once, call it as many times as you want.

2. The anatomy of a C function

Every C function has the same shape:

text
return_type  function_name  (parameter_list) {    // function body    return value;}

A concrete example:

square.c
#include <stdio.h>int square(int x) {       // return type=int, name=square, parameter=int x    return x * x;         // give the value back to the caller}int main() {    int result = square(5);  // result = 25    printf("%d\n", result);    printf("%d\n", square(7));  // you can use the call directly    return 0;}

In Python, the equivalent is:

square.py
def square(x):    return x * xresult = square(5)print(result)print(square(7))

Notice: Python uses def instead of a return type, and there's no type for the parameter. Python is dynamically typed — the same function can take any kind of value.

3. Multiple parameters

max.c
#include <stdio.h>int max_of_two(int a, int b) {    if (a > b) {        return a;    } else {        return b;    }}int main() {    printf("%d\n", max_of_two(7, 12));   // 12    printf("%d\n", max_of_two(99, 3));   // 99    return 0;}
max.py
def max_of_two(a, b):    if a > b:        return a    else:        return bprint(max_of_two(7, 12))print(max_of_two(99, 3))

We named it max_of_two because Python already has a built-in max().

4. void functions — when nothing is returned

Sometimes a function just performs an action (like printing) and doesn't need to return anything. Use the return type void to say "this function returns nothing."

void.c
#include <stdio.h>void print_separator() {    printf("---------------\n");}void greet(int age) {    printf("Hello! You are %d years old.\n", age);}int main() {    greet(20);    print_separator();    greet(30);    return 0;}

In Python there's no void — just leave out the return:

void.py
def print_separator():    print("---------------")def greet(age):    print(f"Hello! You are {age} years old.")greet(20)print_separator()greet(30)

5. Function order in C (declarations)

C requires the compiler to know about a function before you call it. There are two ways to satisfy this:

Option A — Define the function before main

order_a.c
#include <stdio.h>int square(int x) {       // define first    return x * x;}int main() {              // use after    printf("%d\n", square(5));    return 0;}

Option B — Forward declaration (function prototype)

order_b.c
#include <stdio.h>int square(int x);        // declaration: "this function exists, here's its signature"int main() {    printf("%d\n", square(5));   // OK — compiler knows about square    return 0;}int square(int x) {       // definition can come later    return x * x;}

Python doesn't have this requirement — as long as the function is defined before it's called at runtime, you're fine.

6. Local vs global variables (scope)

Variables declared inside a function are local — they only exist while the function is running, and they're invisible to other functions.

scope.c
#include <stdio.h>int global_x = 100;       // global: visible everywherevoid show() {    int local_y = 42;     // local: only exists inside show()    printf("global_x=%d, local_y=%d\n", global_x, local_y);}int main() {    show();    printf("global_x=%d\n", global_x);    // printf("%d", local_y);  // ERROR: local_y doesn't exist here    return 0;}

Best practice: avoid global variables when you can. Pass values into functions as parameters, return results. This keeps each function self-contained and easy to reason about.

Part 3 — Assignments

Requirements

  • 3 problems in total. Estimated time: 1 – 2 hours.
  • Each problem requires a C version (.c) and a Python version (.py).
  • You must define and use the function specified in each problem. Don't put everything in main!
  • Use the exact function name and signature shown for each problem.
  • Compile and run the same way as last week: gcc file.c -o file && ./file for C, python3 file.py for Python.
1Factorial

The factorial of a non-negative integer n, written n!, is the product 1 × 2 × 3 × ... × n. By convention, 0! = 1.

Examples: 5! = 5 × 4 × 3 × 2 × 1 = 120;   3! = 3 × 2 × 1 = 6;   1! = 1.

Write a function int factorial(int n) that takes a non-negative integer and returns n!. Then in main, read n from stdin, call the function, and print the result.

Input format

text
One line containing a single non-negative integer n.Constraint: 0 ≤ n ≤ 12

Output format

text
One line containing the value of n!.

Sample 1

Input

text
5

Output

text
120

Sample 2

Input

text
0

Output

text
1

Sample 3

Input

text
10

Output

text
3628800

Sample 4

Input

text
1

Output

text
1

Required structure

factorial.c
#include <stdio.h>int factorial(int n) {    // TODO: compute and return n!}int main() {    int n;    scanf("%d", &n);    printf("%d\n", factorial(n));    return 0;}
factorial.py
def factorial(n):    # TODO: compute and return n!    passn = int(input())print(factorial(n))
Hint: Use a for loop multiplying from 1 to n. Why is n capped at 12? Because 13! = 6,227,020,800 which is larger than the maximum int (about 2.1 billion). Python doesn't have this problem — its integers can be arbitrarily large — but we use the same constraint to keep the two versions equivalent.
2Reverse Integer

Write a function int reverse_int(int n) that takes a non-negative integer and returns the integer formed by reversing its digits.

  • 1234 → 4321
  • 100 → 1  (leading zeros are dropped, because integers have no leading zeros)
  • 7 → 7
  • 120030 → 30021

Input format

text
One line containing a single non-negative integer n.Constraint: 0 ≤ n ≤ 1,000,000

Output format

text
One line containing the digits of n in reverse order, as an integer.

Sample 1

Input

text
1234

Output

text
4321

Sample 2

Input

text
100

Output

text
1

Sample 3

Input

text
9

Output

text
9

Sample 4

Input

text
120030

Output

text
30021

Required structure

reverse.c
#include <stdio.h>int reverse_int(int n) {    // TODO: return n with its digits reversed}int main() {    int n;    scanf("%d", &n);    printf("%d\n", reverse_int(n));    return 0;}
reverse.py
def reverse_int(n):    # TODO: return n with its digits reversed    passn = int(input())print(reverse_int(n))
Hint: Inside a while loop: take the last digit of n with n % 10, then "shift" the result by doing result = result * 10 + last_digit, and drop the last digit of n with n = n / 10 (in Python, use n //= 10). Stop when n becomes 0. Edge case: n = 0 should output 0 — make sure your loop handles this correctly.
3Primes in a Range

Write a function int is_prime(int n) (you can reuse your logic from Week 1) that returns 1 if n is prime, 0 otherwise.

Then in main: read two integers L and R, and print every prime in the inclusive range [L, R] in increasing order, one per line. If there are no primes in the range, print NONE on a single line.

Input format

text
One line containing two positive integers L and R separated by a space.Constraint: 2 ≤ L ≤ R ≤ 10,000

Output format

text
Each prime in [L, R] on its own line, in increasing order.If no primes exist in the range, print NONE on a single line.

Sample 1

Input

text
2 10

Output

text
2357

Sample 2

Input

text
14 16

Output

text
NONE

Sample 3

Input

text
20 30

Output

text
2329

Sample 4

Input

text
7 7

Output

text
7

Required structure

primes_range.c
#include <stdio.h>int is_prime(int n) {    // TODO: return 1 if n is prime, 0 otherwise}int main() {    int L, R;    scanf("%d %d", &L, &R);    // TODO: loop from L to R, print every prime on its own line.    //       If no primes, print "NONE".    return 0;}
primes_range.py
def is_prime(n):    # TODO: return True if n is prime, False otherwise    passL, R = map(int, input().split())# TODO: loop from L to R, print every prime on its own line.#       If no primes, print "NONE".
Hint: Keep a counter (e.g. int count = 0) that you increment every time you find a prime. After the loop, if count is still 0, print "NONE". Use the √n optimization from Week 1 inside is_prime — the function will be called many times, so making it fast matters.
— Week 2 End —